蓝桥杯-装饰珠

一个抽象的分组背包问题,然后最后的解是要遍历所有DP数组,而不是只有最后一个,因为背包在遍历的过程中扩大了!!!具体为什么我也不清楚。

将M种装饰珠看做M个组,里面值只能选一个,装饰孔看做背包容量。如何正确的选择M个组里面每一个值的选取范围是一个关键问题。按照统计的装饰孔的等级倒着来(从大到小),是一个巧妙的方法。

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
bool cmp(pair<int,vector<int>> a,pair<int,vector<int>> b)
{
    return a.first>b.first;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    vector<int> h(5,0);
    int tol=0;
    for(int i=0;i<6;i++)
    {
        int N;cin>>N;
        for(int j=0;j<N;j++)
        {
            int l;cin>>l;
            h[l]++;
        }
        tol+=N;
    }
    int M;cin>>M;
    vector<pair<int,vector<int>>> a(M+1);
    for(int i=1;i<=M;i++)
    {
        cin>>a[i].first;
        int P;cin>>P;
        a[i].second.resize(P+1);
        for(int j=1;j<=P;j++)
        cin>>a[i].second[j];
    }
    //sort(a.begin(),a.end(),cmp);
    vector<vector<int> > dp(M+1,vector<int>(tol+1,0)); //不要求恰好装满,所以0为初始值
    int vol=0;
    int kind=0;
    for(int i=4;i>=1;i--)//孔数
    {
        vol+=h[i];//动态增加背包容量,限制在正确的范围之内
        for(int k=1;k<=M;k++)//浏览组别
        {
            if(a[k].first==i)
            {
                kind++;//表示第几组
                for (int v = 1; v <= vol; ++v)//第Kind组一件也不选
                {
                    dp[kind][v] = dp[kind - 1][v];
                }
                for(int v=1;v<=vol;v++)//遍历背包容量
                 for(int j=1;j<a[k].second.size();j++)//第kind组里面只选一件,相互对比
                 {
                     if(v<j)
                     continue;
                     else
                     dp[kind][v]=max(dp[kind][v],dp[kind-1][v-j]+a[k].second[j]);
                 }
            }
        }
    }
    //cout<<dp[kind][vol]<<endl;// 背包扩大,最优解不一定是这个
    cout<<*max_element(dp[kind].begin(),dp[kind].end())<<'\n';
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值