P1064 金明的预算方案 分组背包 解题报告

题目链接https://www.luogu.com.cn/problem/P1064

题目中描述是一个主件带0到2个附件,买附件必须买主件,那么可以将每一个主件的购买方案进行分组

比如 一个主件A 附带附件2个 B 和 C

购买方案就有四种 A,A+B,A+C,A+B+C。

那么这其实就和多重背包类似 多重背包代码如下

for(int i = 0; i < weight.size(); i++) { // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            // 以上为01背包,然后加一个遍历个数
            for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数
                dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
            }
        }

假如一个物品有n个,那么一个物品可以买1,2,3,.....,n件,等同于有n种方案购买,而这个分组背包只有 1(0附件),2(1附件),4(2附件)种方案,所以只要写成多重背包的变形版就可以了。

AC代码如下

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int pri[62];
int imp[62];
int aff[62];
int flag[62][2];
int t[62];
struct group
{
    int sum=0;//方案个数
    int v[4];//价值
    int w[4];//重量
}s[62];//分组
int dp[32002];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&pri[i],&imp[i],&aff[i]);
        if(aff[i]!=0)
        flag[aff[i]][t[aff[i]]++]=i;
    }
    int tt=0;
    for(int i=1;i<=m;i++)
    {
      if(aff[i]==0)
      {
        if(t[i]==2)
        {
            s[++tt].sum=4;
            s[tt].v[0]=pri[i]*imp[i];
            s[tt].w[0]=pri[i];
            s[tt].v[1]=pri[i]*imp[i]+pri[flag[i][0]]*imp[flag[i][0]];
            s[tt].w[1]=pri[i]+pri[flag[i][0]];
            s[tt].v[2]=pri[i]*imp[i]+pri[flag[i][0]]*imp[flag[i][0]]+pri[flag[i][1]]*imp[flag[i][1]];
            s[tt].w[2]=pri[i]+pri[flag[i][0]]+pri[flag[i][1]];
            s[tt].v[3]=pri[i]*imp[i]+pri[flag[i][1]]*imp[flag[i][1]];
            s[tt].w[3]=pri[i]+pri[flag[i][1]];
        }
        if(t[i]==1)
        {
            s[++tt].sum=2;
            s[tt].v[0]=pri[i]*imp[i];
            s[tt].w[0]=pri[i];
            s[tt].v[1]=pri[i]*imp[i]+pri[flag[i][0]]*imp[flag[i][0]];
            s[tt].w[1]=pri[i]+pri[flag[i][0]];
        }
        if(t[i]==0)
        {
            s[++tt].sum=1;
            s[tt].v[0]=pri[i]*imp[i];
            s[tt].w[0]=pri[i];
        }
      }
    }//用来分组
    
    for(int i=1;i<=tt;i++)
     for(int j=n;j>0;j--)
      for(int k=0;k<s[i].sum;k++)
      if(j-s[i].w[k]>=0)
       dp[j]=max(dp[j],dp[j-s[i].w[k]]+s[i].v[k]);//多重背包类似写法 滚动数组
       
      printf("%d",dp[n]);

    return 0;
}

不过我这个求分组的写法过于繁琐哈哈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值