题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3535
题目意思:给出两个数n,T,分别表示有n个任务集合,T的总时间,对于每个任务集合有两个属性m和type,表示这个任务集合内有m个任务,类型为type,当type=0的时候必须执行一个这个集合内的一个任务,type=1的时候最多可以执行一项,type=2随便你做不做。
思路:不愧是10年多校的题,看到的时候真的是懵逼了。颠覆了对背包的看法,但是这个题肯定是一个混合背包(这个还是看出来了)!首先要想一个框架来涵盖所有的情况,我们可以建立二维dp数组dp[i][j]来表示有i个任务集合时剩余j的时间。
对于type=0的时候:
由于至少选一项类比另一背包的思想,从前一个任务集合那里转移过来,也可以从自己这里转移过来(选择多个),但是数组要设置成-inf来判断来判断是否可以从上一组任务集合里转移过来判断是否取了这个这个集合里的任务。
转移方程:dp[i][k]=max(dp[i][k],dp[i][k-co[j]]+ha[j],dp[i-1][k-co[j]]+ha[j]);
对于type=1的时候:
这个时候可选可不选了,直接复制上一组的内容然后。由于最多选一个所以只能从上一个任务集合转移过来。
转移方程: dp[i][k]=max(dp[i][k],dp[i-1][k-co[j]]+ha[j]);
对于type=2的时候:
这个时候也是可选可不选,直接复制上一组内容然后,由于可多选,所以可以从上一个任务转移集合转移过来,也可以的时候从自己转移过来。
转移方程:dp[i][k]=max(dp[i][k],dp[i][k-co[j]]+ha[j],dp[i-1][k-co[j]]+ha[j]);
个人认为比较难的地方:必须要选一个情况。这是我看了题解才想懂的地方,这是一道好题以后要多复习复习。
总结:对于是否选一个可以把数组全部设置成-inf,看是否可以从上一个任务哪里转移,以判断是否选择了。
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=200; 21 using namespace std; 22 typedef long long LL; 23 typedef int II; 24 II dp[N][N]; 25 II n,T; 26 II co[N],ha[N]; 27 int main() { 28 ios::sync_with_stdio(false);cin.tie(0); 29 while(cin>>n>>T){ 30 mem(dp,0); 31 for(int i=1;i<=n;i++){ 32 int m,type; 33 cin>>m>>type; 34 for(int j=1;j<=m;j++) cin>>co[j]>>ha[j]; 35 if(type==0){ 36 for(int j=0;j<=T;j++) dp[i][j]=-inf; 37 for(int j=1;j<=m;j++) 38 for(int k=T;k>=co[j];k--){ 39 dp[i][k]=max(dp[i][k],dp[i][k-co[j]]+ha[j]); 40 dp[i][k]=max(dp[i][k],dp[i-1][k-co[j]]+ha[j]); 41 } 42 } 43 else if(type==1){ 44 for(int j=0;j<=T;j++) dp[i][j]=dp[i-1][j]; 45 for(int j=1;j<=m;j++) 46 for(int k=T;k>=co[j];k--){ 47 dp[i][k]=max(dp[i][k],dp[i-1][k-co[j]]+ha[j]); 48 } 49 } 50 else{ 51 for(int j=0;j<=T;j++) dp[i][j]=dp[i-1][j]; 52 for(int j=1;j<=m;j++) 53 for(int k=T;k>=co[j];k--){ 54 dp[i][k]=max(dp[i][k],dp[i][k-co[j]]+ha[j]); 55 dp[i][k]=max(dp[i][k],dp[i-1][k-co[j]]+ha[j]); 56 } 57 } 58 } 59 dp[n][T]=max(dp[n][T],-1); 60 cout<<dp[n][T]<<endl; 61 } 62 return 0; 63 }