TZOJ:3789: Process the Tasks

这是一道经典的双塔DP题,建议没学过双塔的人先去学了再来弄这题吧.

最初始的双塔题好像是ZOJ上的那道------搭建双塔

但我学了把那道题弄懂后,再来写这道题的时候,还是没有任何思路,可能是我蠢爆了........

无奈之下我翻了好几个博客去找题解,但几乎所有博客上讲的都有点粗枝大叶的,不够详细,我还得自己走几下代码,才能弄懂大致的思路,其中我看的一个博客,将大致的思路讲清楚了.

ZOJ 3331 Process the Tasks(双塔DP)_Dacc123的博客-CSDN博客

可以去翻一翻

dp[i][j] 表示执行第i个任务,机器A和机器B的时间差

双塔DP 顾名思义可以把A机器和B机器看作是两座塔,如果把当前任务放在哪个塔上,那么哪个塔的高度就会增加

每次放任务,都会有两个选择,要么放在A塔,要么放在B塔。如果放在高的塔上,根据题意在同一个机器上必要上一个任务完成

时才能进行下一个任务,所以等高的塔完成上一个任务是,A,B都是空闲的了,这个是在高的塔上放任务,时间差就是这个任务的时间

如果放在低的塔上,那么在之前的差值上加上这个任务的时间

这段文字贵为重要,代码里if语句中写的四行状态转移方程都是在这段文字的理解上弄得,但各方面细节讲的不够清晰,我在这里稍微弄清一下思路,方便ACM里来学双塔的人方便一点.

好了直接上代码把

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int dp[105][205];
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,ta,tb;
		cin>>n;
		memset(dp,inf,sizeof(dp));
		dp[0][100]=0;
		for(int i=1;i<=n;i++)
		{
			cin>>ta>>tb;
			/*首先我要说明一下,为什么j要分为正和负两种情况来做, 
			因为双塔DP中dp[i][j]中的j记录的是两个塔之间的高度差,
			由于这里两个塔往上搭同一块积木所产生的高度不同(也就是两个机器做同一个任务所用时间不同)
			所以要以100为分界线,100一下表示B塔为高塔,100以上表示A为高塔
			为什么要以100为分界线呢?题目中给出了每个ta,tb的范围,所以差值绝不超过100; 
			*/
			for(int j=-99;j<=99;j++)
			{
				if(dp[i-1][j+100]==inf) continue;
				if(j<0)//j<0的时候说明此时高塔为B 
				{
					dp[i][100-tb]=min(dp[i][100-tb],dp[i-1][100+j]+tb);
					//这里由于B为高塔,那么[100-tb]表示把这个任务放在高塔上来做 
					dp[i][j+ta+100]=min(dp[i][j+ta+100],dp[i-1][100+j]+max(0,j+ta));
					//这里A为低塔,[j+ta+100]那么说明是在原本差值为j的情况下给A塔来做这个任务
					//后面有个max是因为,你把这个任务给A塔后,后产生两种情况
					//第一种,A塔还是比B塔低,说明高塔还是高塔,没有变得更高.
					//第二种,A塔比B塔高了,那么高出多少?高出了j+ta(因为j为负的) 
				}
				else//此时说明高塔为A
				{//这里上同,不再赘述了 
					dp[i][ta+100]=min(dp[i][ta+100],dp[i-1][j+100]+ta);
					dp[i][j-tb+100]=min(dp[i][j-tb+100],dp[i-1][j+100]+max(0,tb-j));
				} 
			}
		}
		int res=inf;
		for(int i=-99;i<=99;i++)
			res=min(res,dp[n][i+100]);
		cout<<res<<endl;
	}
	return 0;
}

上一篇:5880: (a+b)×c


下一篇:RSYNC 3.2.3 源码安装配置