(混合背包)HDU3535AreYouBusy

HDU3535AreYouBusy

题意&思路:

给时间T和工作集合n,有三种类型的集合:最少选一个工作,最多选一个工作,任选。问在T时间时完成工作的幸福度。
混合背包问题,有点难,看了题解才慢慢理解。
用dp[i][j]表示在第i个集合,时间为j的最大幸福度。
1、至少选一项。
将dp[i][j]全部赋值负无穷,这样就可以保证不会出现一个都不选的情况。
dp[i][j]=max{dp[i][j],dp[i-1][j-w[k]]+v[k],dp[i][j-w[k]]+v[k]},dp[i][j]表示不选当前工作;dp[i-1][j-w[k]]+v[k]表示第一次选本组工作,由于初始值为负无穷,所以第一次一定可以去一个工作;dp[i][j-w[k]]+v[k]表示选本组的工作,但不是第一次。
2、至多选一项。
最多选一项就是要么选,要么不选。
对于不选dp[i][j]=dp[i-1][j];对于选就是dp[i][j]=dp[i-1][j-w[k]]+v[k];
所以将dp[i][j]先赋值为dp[i-1][j]。
状态转移方程就是dp[i][j]=max{dp[i][j],dp[i-1][j-w[k]]+v[k]}。
3、任选
就是普通的01背包问题。
先将dp[i][j]赋值为dp[i-1][j]。
状态转移方程为dp[i][j]=max{dp[i][j],dp[i][j-w[k]]+v[k])。

代码:

#include<bits/stdc++.h>
const int N=1e6+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
int w[200],v[200],dp[200][200];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,t;
	while(cin>>n>>t)
	{
		memset(dp,0,sizeof(dp));
		int i,j,k;
		for(i=1;i<=n;i++)
		{
			int m,p;
			cin>>m>>p;
			for(j=1;j<=m;j++)
				cin>>w[j]>>v[j];
			if(p==0)
			{
				for(j=0;j<=t;j++)
					dp[i][j]=minn;
				for(j=1;j<=m;j++)
					for(k=t;k>=w[j];k--)
						dp[i][k]=max(max(dp[i][k],dp[i][k-w[j]]+v[j]),dp[i-1][k-w[j]]+v[j]);
			}
			if(p==1)
			{
				for(j=0;j<=t;j++)
					dp[i][j]=dp[i-1][j];
				for(j=1;j<=m;j++)
					for(k=t;k>=w[j];k--)
						dp[i][k]=max(dp[i][k],dp[i-1][k-w[j]]+v[j]);
			}
			if(p==2)
			{
				for(j=0;j<=t;j++)
					dp[i][j]=dp[i-1][j];
				for(j=1;j<=m;j++)
					for(k=t;k>=w[j];k--)
						dp[i][k]=max(dp[i][k],dp[i][k-w[j]]+v[j]);		
			}
		}
		int ans=max(dp[n][t],-1);
		cout<<ans<<endl;
	}
	return 0;
}

发布了78 篇原创文章 · 获赞 0 · 访问量 1419

猜你喜欢

转载自blog.csdn.net/Z7784562/article/details/103873624
今日推荐