描述
桃子在2019年参加EC-Final的时候,获得了一个背包,他现在有若干个物品,每个物品都有价值,体积以及颜色三个属性,桃子为了使自己的背包里面的东西颜色丰富一点,想让它有不少于k个颜色的物品,求背包里能装最大的价值。
输入
输入第一行为测试样例组数T(1<=T<=100)。
对于每组数据第一行包含三个正整数n(1<=n<=100),k(1<=k<=5),v(1<=v<=200),分别代表n个物品,想要的颜色种数,背包的容量。
接下来n行,每行三个正整数ai(1<=ai<=1000),vi(1<=vi<=v),ci(1<=ci<=n),分别代表每个物品的价值,体积,颜色。
输出
对于每组数据,输出一个整数代表背包能放不少于k种颜色的最大价值。
样例输入
3
5 1 10
3 2 1
5 8 1
7 9 1
1 2 2
2 2 3
5 2 10
3 2 1
5 8 1
7 9 1
1 2 2
2 2 3
5 3 10
3 2 1
5 8 1
7 9 1
1 2 2
2 2 3
样例输出
8
7
6
思路:
一开感觉有点无从下手,看了学长的提示后,如拨云见日。发现这是一道01背包+分组背包+有限制的01背包;
首先考虑选哪种颜色,这种颜色中选几个,体积是多少,价值又是多少,所以直接先对每种颜色做一个01背包求出该颜色下背包中各体积所能拥有的最值是多少;这样以来问题就变成了要选什么颜色,这个颜色选多少体积,这就变成了一个分组背包的问题
这样就只剩下K这个条件了想要满足这个条件则在对分组背包进行打表时需要满足dp_c[c-1][j-wt]>0&&dp_w[i][wt]>0||c==1,相当于是一个要装满的背包问题。
由于问题问的是至少k种所以还要在dp_c[k][v]到dp_c[n][v]中找最值;
背包真是个神奇的东西。
代码:
#include<bits/stdc++.h>
using namespace std;
int dp_w[101][201],dp_c[101][201];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k,v,val,w,c;
memset(dp_c,0,sizeof dp_c);
memset(dp_w,0,sizeof dp_w);
scanf("%d%d%d",&n,&k,&v);
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&val,&w,&c);
for(int j=v;j>=w;j--)
dp_w[c][j]=max(dp_w[c][j],dp_w[c][j-w]+val);//每种颜色个体积的最大价值;相当与制造v*颜色个数的新物品
}
for(int i=1;i<=n;i++)
{
if(dp_w[i][v]==0)continue;
for(int c=i;c;c--)
{
for(int j=v;j;j--)
{
for(int wt=1;wt<=j;wt++)
if(dp_w[i][wt]&&(dp_c[c-1][j-wt]||c==1))dp_c[c][j]=max(dp_c[c][j],dp_c[c-1][j-wt]+dp_w[i][wt]);//每种颜色最多选一个体积
}
}
}
int mx=dp_c[k][v];
for(int i=k;i<=n;i++)if(dp_c[i][v]>=mx)mx=dp_c[i][v];else break;
printf("%d\n",mx);
}
return 0;
}
若有什么错误,欢迎指正^ _ ^ 。