题目:
链接:点击打开链接
题意:
xx喜欢收集鞋子,n,m,k分别表示鞋子的总数,xx的钱和鞋子的品牌数目。然后给出每个鞋子的信息有:a,是那种品牌,b,鞋子的标价,c,收藏鞋子得到的价值。对于一个收藏家来说,每种品牌的鞋子只收集一种,求出xx能够得到的最大的收藏价值。
算法:
分组背包问题。
思路:
m总的钱数是背包容量,k品牌数是组数。用数组结构体保存每种鞋子的信息,d[i][j].w表示第i种品牌的鞋子中的第j个鞋子的标价,d[i][j].v表示第i种品牌的鞋子中的第j个鞋子价值。状态转移方程dp[i][j]表示前i组品牌中用掉j钱得到的最大的价值。状态转移可以是前一组少取一个,即dp[i-1][p-d[i][j].w]+d[i][j].v,也可以是当前组少取一种,即dp[i][p-d[i][j].w]+d[i][j].v。初始化第一组置为0,其他组置为负无穷,因为只有上一组达到要求才能进行下一组,每组必须取一个。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
int v;
int w;
}d[20][110];
int num[20];
int dp[20][10010];
int main()
{
//freopen("input.txt","r",stdin);
int n,m,k;
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);
d[a][num[a]].w = b;
d[a][num[a]].v = c;
num[a]++;//num[a]表示第a组的鞋的个数
}
memset(dp[0],0,sizeof(dp[0]));
for(int i=1; i<=k; i++)
{
for(int j=0; j<num[i]; j++)
{
for(int p=m; p>=d[i][j].w; p--)
{
if(dp[i-1][p-d[i][j].w] != -1)
dp[i][p] = max(dp[i][p],dp[i-1][p-d[i][j].w]+d[i][j].v);
if(dp[i][p-d[i][j].w] != -1)
dp[i][p] = max(dp[i][p],dp[i][p-d[i][j].w]+d[i][j].v);
}
}
}
if(dp[k][m] == -1)
printf("Impossible\n");
else
printf("%d\n",dp[k][m]);
}
return 0;
}