1 #include<iostream> 2 using namespace std; 3 int Max(int a,int b,int c){ 4 if(a<b) a=b; 5 if(a<c) a=c; 6 return a; 7 } 8 int f[105][105]; 9 int main() 10 { 11 int n,T,i,j,k,m,s,c,g; 12 while(~scanf("%d%d",&n,&T)){ 13 memset(f,0,sizeof(f)); 14 for(i=1;i<=n;i++){ 15 scanf("%d%d",&m,&s); 16 for(j=0;j<=T;j++) 17 f[i][j]=s?f[i-1][j]:INT_MIN; //如果 s==0 需赋值为无穷小, 18 //这样才能保证至少使用一次 ,因为一件也不使用对应结果就为负无穷, 19 // s!=0时,要先传递f[i-1][j]的值给f[i][j] 20 for(j=1;j<=m;j++){ 21 scanf("%d%d",&c,&g); 22 for(k=T;k>=c;k--){ //递推顺序不能颠倒,因为每种工作只能被完成一次 23 //如 01背包中的滚动数组 24 if(s==1) f[i][k]=max(f[i][k],f[i-1][k-c]+g); //01背包模型最多能选取一件 25 else f[i][k]=Max(f[i][k],f[i-1][k-c]+g,f[i][k-c]+g); //可以选取多件, 26 //所以在 max中多加了了一个 f[i][k-c]+g 以致可以选取多个 27 } 28 } 29 } 30 printf("%d\n",max(f[n][T],-1)); //假如不存在解,f[n][T]则为负无穷 31 } 32 return 0; 33 }
一种混合+组合背包问题!很经典