HDU 3535 AreYouBusy(混合背包)
來源:程序員人生 發布時間:2014-11-07 08:57:46 閱讀次數:3043次
HDU3535 AreYouBusy(混合背包)
http://acm.hdu.edu.cn/showproblem.php?pid=3535
題意:
給你n個工作集合,給你T的時間去做它們。給你m和s,說明這個工作集合有m件事可以做,它們是s類的工作集合(s=0,1,2,s=0說明這m件事中最少得做1件,s=1說明這m件事中最多只能做1件,s=2說明這m件事你可以做也能夠不做)。再給你ci和gi代表你做這件事要用ci的時間,能取得gi的快樂值。求在T的時間內你能取得的最大快樂值。
分析:
首先如果存在最優解, 我們可以互換不同工作集合的處理順序, 仍然能得到最優解. 那末我們下面只需要處理每一個單獨的工作集合便可.
令dp[i][j]==x表示處理完前i組工作集,所花時間<=j時的快樂值為x。每得到1組工作就進行1次DP,所以dp[i]為第i組的結果。下面對3種情況進行討論。
1. 該集合內最少要選1件工作時. 要保證最少選1個第i類工作, 可以從第i⑴類的結果dp[i⑴]來更新dp[i].也能夠用 01背包的思想, 從本類的前1個工作更新后1個工作.
初始化:dp[i]全為負無窮.(即-INF)
狀態轉移方程為:
dp[i][k]=max{dp[i][k],dp[i⑴][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }
2. 該集合內最多選1件工作時. 只能從上1層的結果dp[i⑴]來更新dp[i]了.(想一想為何)
初始化:dp[i]==dp[i⑴].
狀態轉移方程為dp[i][k]=max{dp[i][k],dp[i⑴][k-cost[j]]+val[k]}.
3. 該集合內工作可以隨意選. 這就是1個普通的01背包問題了.
初始化:dp[i]==dp[i⑴].
狀態轉移方程為:
dp[i][k]=max{dp[i][k],dp[i⑴][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }
終究所求:dp[n][t]的值.
AC代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;
#define INF 1e8
int n;
int t;
int dp[maxn][maxn];
int cost[maxn];
int val[maxn];
int main()
{
while(scanf("%d%d",&n,&t)==2)
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
int m,s;
scanf("%d%d",&m,&s);
for(int k=1;k<=m;k++)
scanf("%d%d",&cost[k],&val[k]);
if(s==0)//最少選1個的01背包問題
{
for(int j=0;j<=t;j++) dp[i][j]=-INF;
for(int k=1;k<=m;k++)
for(int j=t;j>=cost[k];j--)
{
dp[i][j] = max( dp[i][j] , dp[i][j-cost[k]]+val[k] ); //1
dp[i][j] = max( dp[i][j] , dp[i⑴][j-cost[k]]+val[k] );//2
//上面兩句順序互換就會出錯!為何?
}
}
else if(s==1)//最多選1個的背包問題
{
for(int j=0;j<=t;j++) dp[i][j]=dp[i⑴][j];
for(int k=1;k<=m;k++)
for(int j=t;j>=cost[k];j--)//j可以正序或逆序枚舉
dp[i][j] = max( dp[i][j] , dp[i⑴][j-cost[k]]+val[k] );
}
else if(s==2)//隨意選的01背包問題
{
for(int j=0;j<=t;j++) dp[i][j]=dp[i⑴][j];
for(int k=1;k<=m;k++)
for(int j=t;j>=cost[k];j--)//j只能逆序枚舉
dp[i][j] = max( dp[i][j] , dp[i][j-cost[k]]+val[k] );
}
}
int ans = max(dp[n][t],⑴);
printf("%d
",ans);
}
return 0;
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈