洛谷P2224產品加工(DP)

爱艺诗篇發表於2024-10-10

[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\)