[HNOI2001] 產品加工
題目描述
某加工廠有 A、B 兩臺機器,來加工的產品可以由其中任何一臺機器完成,或者兩臺機器共同完成。由於受到機器效能和產品特性的限制,不同的機器加工同一產品所需的時間會不同,若同時由兩臺機器共同進行加工,所完成任務又會不同。
某一天,加工廠接到 \(n\) 個產品加工的任務,每個任務的工作量不盡一樣。
你的任務就是:已知每個任務在 A 機器上加工所需的時間 \(t_1\),B 機器上加工所需的時間 \(t_2\) 及由兩臺機器共同加工所需的時間 \(t_3\),請你合理安排任務的排程順序,使完成所有 \(n\) 個任務的總時間最少。
輸入格式
第一行為一個整數 \(n\)。
接下來 \(n\) 行,每行三個非負整數 \(t_1,t_2,t_3\),分別表示第 \(i\) 個任務在 A 機器上加工、B 機器上加工、兩臺機器共同加工所需要的時間。如果所給的時間 \(t_1\) 或 \(t_2\) 為 \(0\) 表示任務不能在該臺機器上加工,如果 \(t_3\) 為 \(0\) 表示任務不能同時由兩臺機器加工。
輸出格式
僅一行一個整數,表示完成所有 \(n\) 個任務的最少總時間。
關於本題:
也是頭一次見這種狀態定義方式比較特殊的,我們發現對於任務排序不太好做,考慮dp,那麼狀態的設計呢
Sol:
(1).f[i][t1][t2]:表示前i個任務,A用時t1,B用時t2是否可行
我們發現maxt大約在6000*5=30000,空間時間都不允許,考慮降維
(2).f[i][t1]:表示前i個任務,A用時t1,B的最小用時,這一步是把B的狀態取消固定
但是此時發現空間為 6000*30000=180000000=1.8 * 10^8,MLE
(3).轉移時發現f[i]之和f[i-1]有關,滾動一下就行了
滾動後記得陣列賦初始值,然後你就要用memset每次對f[last]這一行賦值了對嗎?你會TLE得理所應當。
原因是多次呼叫memset使程式效率降低,那我們乾脆就用臨時變數算了,由於再滾動了一維,所以maxt要倒序列舉
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
const int N=3e5+7;
int n,ans=0x3f3f3f3f,s;
int x,y,z,maxt;
int f[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;++i){
cin>>x>>y>>z;
maxt+=max(max(x,y),z);
for(int j=maxt;j>=0;j--){
int tmp=0x3f3f3f3f;
if(x&&j>=x) tmp=min(tmp,f[j-x]);
if(y) tmp=min(tmp,f[j]+y);
if(z&&j>=z) tmp=min(tmp,f[j-z]+z);
f[j]=tmp;
}
}
for(int i=0;i<=maxt;++i)
ans=min(ans,max(i,f[i]));
cout<<ans<<'\n';
return 0;
}
樣例 #1
樣例輸入 #1
5
2 1 0
0 5 0
2 4 1
0 0 3
2 1 1
樣例輸出 #1
9
提示
對於所有資料,有 \(1\le n\le 6\times 10^3\), \(0\le t_1,t_2,t_3\le 5\)。