题意:每一组物品都有一个盒子,要买该组的物品必须先要买盒子,问能够获得的价值最大是多少。


解题思路:这题有点像分组背包,但是每一组里面要买物品必须要先买盒子。其实我的想法还是和分组背包的思路一样,只是把盒子看成一个单独的物品,dp[i][j]表示前i组物品,容量为j时的最大价值。为了防止盒子没有买就买了这一组的物品,我们最开始的dp[i][j]赋值为-1,在该组里做一次01背包,同样,还是需要做一次分类,该组里面的物品是第一个放入的还是之前已放入过其他物品。但如果认为这样就完成任务了,那么就game over了,如果该组没有一个放入背包,那么dp[i]的所有值都会为-1,连之前的状态都会丢失,所以还要把之前的值复制过来。



#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n,m,box[55],cost[55][11],value[55][11];
int dp[55][100005],num[55];

int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(dp,-1,sizeof(dp));
		memset(dp[0],0,sizeof(dp[0]));
		for(int i = 1; i <= n; i++)
		{
			scanf("%d",&box[i]);
			scanf("%d",&num[i]);
			for(int j = 1; j <= num[i]; j++)
				scanf("%d%d",&cost[i][j],&value[i][j]);
		}
		int ans = 0;
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= num[i]; j++)
				for(int v = m; v >= cost[i][j]; v--)
				{
					if(dp[i][v-cost[i][j]] != -1)	//之前就放过物品了,直接01背包
						dp[i][v] = max(dp[i][v],dp[i][v-cost[i][j]]+value[i][j]);
					if(v >= box[i] + cost[i][j])	//该组里面第一个放入背包的物品
					{
						if(dp[i-1][v-box[i]-cost[i][j]] != -1)
							dp[i][v] = max(dp[i][v],dp[i-1][v-box[i]-cost[i][j]]+value[i][j]);
					}
				}
			for(int v = 0; v <= m; v++)
				dp[i][v] = max(dp[i][v],dp[i-1][v]);
		}
		printf("%d\n",dp[n][m]);
	}
	return 0;
}