[HNOI2001]产品加工

洛谷题面

清新 \(\rm DP\) 题。

题目大意

\(n\) 个任务,第 \(i\) 个任务可以给 A 机器做,用时 \(t_1[i]\);给 B 机器做,用时 \(t_2[i]\);给 A 机器和 B 机器同时做,用时 \(t_3[i]\)

求最小用时。

当对应 \(t[i]=0\) 时,代表不能给这个机器或这两个机器做。

题目分析

\(dp[i][j][k]\) 表示完成了前 \(i\) 个任务,第一台机器耗时为 \(j\),另一台耗时为 \(k\),此时的最小总用时。

最终答案即为 \(\min\{dp[n][j][k]\}\)

先不论时间,即便用上滚动数组优化,空间复杂度也已经炸成花了,我们考虑一个巧妙的优化:

\(dp[i][j]\) 表示完成了前 \(i\) 个 任务,第一台机器耗时为 \(j\) 时第二台机器的最小耗时。

直接将 【第二台机器耗时】 这个东西干掉了!(

本题中状态转移方程并非重点,但还是摆上来:

\(dp[i][j]=\min\{dp[i-1][j]+t2[i],dp[i-1][j-t1[i]],dp[i-1][j-t3[i]]+t3[i]\}\)

仍然是可以滚动优化的。

时间复杂度 \(\mathcal{O}(nk)\),空间复杂度 \(\mathcal{O}(ns)\)

\(s\)\(t1,t2,t3\) 的取值范围,\(k\)\(\sum_{i=1}^n \max\{t1[i],t2[i],t3[i]\}\)\(k\) 最大为 \(6\times 10^3\times5=3\times 10^4\)

可以通过本题。

代码

//2022/1/8

const int INF=0x3f3f3f3f;

const int ma1=6005,ma2=30005;

int t1[ma1],t2[ma1],t3[ma1];

int dp[2][ma2];

int n;

int main(void)
{
	n=read();
	
	mst(dp,0x3f);
	
	dp[0][0]=0;
	
	for(register int i=1;i<=n;i++)
	{
		t1[i]=read(),t2[i]=read(),t3[i]=read();
	}
	
	int sum(0);
	
	for(register int i=1;i<=n;i++)
	{
		mst(dp[i&1],0x3f);
		 
		sum+=max({t1[i],t2[i],t3[i]});
		
		for(register int j=0;j<=sum;j++)
		{	
			if(t2[i]!=0) 
			{
				dp[i&1][j]=min(dp[i&1][j],dp[i&1^1][j]+t2[i]);
			}
			
			if(t1[i]!=0 && j>=t1[i]) 
			{
				dp[i&1][j]=min(dp[i&1][j],dp[i&1^1][j-t1[i]]);
			}
			
			if(t3[i]!=0 && j>=t3[i]) 
			{
				dp[i&1][j]=min(dp[i&1][j],dp[i&1^1][j-t3[i]]+t3[i]);
			}
		}
	}
	
	int ans=INF;
	
	for(register int i=0;i<=sum;i++)
	{
		ans=min(ans,max(i,dp[n&1][i]));
	}
	
	printf("%d\n",ans);
	
	return 0;
}
posted @ 2022-01-08 16:36  Coros_Trusds  阅读(29)  评论(0编辑  收藏  举报