TOJ 5873: 桃子的背包

描述

桃子在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;
}

若有什么错误,欢迎指正^ _ ^ 。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值