题目链接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;
}
不过我这个求分组的写法过于繁琐哈哈