hdu 3535 AreYouBusy

hdu   3535   AreYouBusy              题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3535

                              

题目大意:小A要在一段时间内做一些工作,给出工作大类的数量n、总时间t。共有0、1、2三大类工作,0是老板要求至少做其中一项的、1是小A自己想做,但最多从中选一项的、2是随便的(注意所有工作只能做一次),每一大类里又有m种工作,每种工作有两个参数c和g,分别代表花费的时间和得到的快乐值,求最大快乐值。

题目分析:算是个混合背包吧,考虑三种情况,如下。

    至少要做一项的0:需要用到此刻状态(不装、再装)、上一状态(只装)。处理这一大类工作时先把此状态数组赋为-inf,这是为了不会出现一种工作都不选的情况。然后此种状态下的状态转移方程就是dp[此状态][i]=max(dp[此状态][i],dp[上一状态][i-c]+g,dp[此状态][i-c]+g);

    最多做一项的1:把上一状态全数复制到当前状态后开始装这一大类物品,这次复制为的是保留上一状态,写操作只在当前状态上。这一类工作可以选择做或不做,状态转移方程dp[当前状态][i]=max(dp[当前状态][i],dp[上一状态][i-c]+g);

    随便的2:就是个普通0-1背包。

还有个值得一提的地方,此题初学滚动数组,用的2×一维的开关变量控制的滚动数组,是从hdu1024市面上的代码里学来的。

code:

#include<stdio.h>
#include<string.h>
int max(int a,int b)
{
	return a>b?a:b;
}
int main()
{
	int m,n,t,s,i,j,c,g,cur=0,dp[2][110];
	while(scanf("%d%d",&n,&t)!=EOF)
	{
		memset(dp,0,sizeof(dp));
		while(n--)
		{
			scanf("%d%d",&m,&s);
			switch(s)
			{
				case 0:
				for(i=0;i<=t;i++)dp[cur][i]=-99999;
				while(m--)
				{
					scanf("%d%d",&c,&g);
					for(i=t;i>=c;i--)
					{
						dp[cur][i]=max(max(dp[cur][i],dp[1-cur][i-c]+g),dp[cur][i-c]+g);
					}
				}break;
				case 1:
				for(i=0;i<=t;i++)dp[cur][i]=dp[1-cur][i];
				while(m--)
				{
					scanf("%d%d",&c,&g);
					for(i=t;i>=c;i--)
					{ 
						dp[cur][i]=max(dp[cur][i],dp[1-cur][i-c]+g);
					}
				}break;
				case 2:
				cur=1-cur;//懒得再赋值了,一样
				while(m--)
				{
					scanf("%d%d",&c,&g);
					for(i=t;i>=c;i--)
					{
						dp[cur][i]=max(dp[cur][i],dp[cur][i-c]+g);
					}
				}
			}
			cur=1-cur;
		}
		for(i=0;i<=t;i++)
		{
			n=max(n,dp[1-cur][i]);
		}
		printf("%d\n",n);
	}
	return 0;
}

PS:参考了discuss里的代码,这次discuss里只有一篇代码……还有很多值得修改的地方,我删了不少微笑

开始看代码有很多不懂,感谢大神http://www.cnblogs.com/coredux/archive/2012/07/26/2610868.html





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值