题意:有S款运动鞋,一个n件,总钱数为m,求不超过总钱数且每款鞋子至少买一双的情况下,使价值最大。如果 有一款买不到,就输出“Impossible"。
解题思路:分组背包,和背包九讲里面不同的是,这里要每一组至少有一个。为了保证每一组都有被取,dp[i][j]初始化为-1,表示前i组,背包容量为j时可获得的最大价值。在每一组中选择时,一定要注意这一组的物品是第一次选,还是之前已经选了多个物品。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 105;
int num[11],cost[11][maxn],value[11][maxn];
int n,m,k,dp[11][10005];
int main()
{
int a,b,c;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(num,0,sizeof(num));
memset(dp,-1,sizeof(dp));
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d",&a,&b,&c);
num[a]++;
cost[a][num[a]] = b;
value[a][num[a]] = c;
}
memset(dp[0],0,sizeof(dp[0]));
for(int i = 1; i <= k; 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) //从本组里面取,之前可能抽取了多个
dp[i][v] = max(dp[i][v],dp[i][v-cost[i][j]]+value[i][j]);
if(dp[i-1][v-cost[i][j]] != -1) //从本组中抽取的第一个
dp[i][v] = max(dp[i][v],dp[i-1][v-cost[i][j]]+value[i][j]);
/*
顺序不能调转,因为如果代价为0,调转的话,有可能出现先有dp[i][v] = dp[i-1][v-0]+w,再有
dp[i][v] = dp[i][v-0]+w = dp[i-1][v-0]+w+w,所以物品取了两次
*/
}
}
if(dp[k][m] == -1)
printf("Impossible\n");
else printf("%d\n",dp[k][m]);
}
return 0;
}