原题
思路概述
题意分析
给定一个体积为 \(n\) 的背包和 \(m\) 个物品。每个物品通过 \((\text{价值},\text{体积})\) 的形式表示为 \((p_i·v_i,v_i)\),同时部分物品还对应了唯一的一个前驱 \(q_i\),只有前驱被选入背包的时候该物品才能被选取。求最后能取得的最大价值。
思路简述
有点意思的01背包变式,对于一个没有对应主件也没有对应附件的物品,操作策略与01背包无异;对于相互对应的主件和附件,由于每个主件最多两个附件(为方便表述,笔者称相互对应的主件与附件为一组物品),其所有的选取情况只有最多四种:只选取主件、选取主件和第一个附件、选取主件和第二个附件、同时选取主件和所有附件。
算法实现
关于背包的第二重循环
由于本题中一组物品的所有选取方式对应了多个不同的体积,所以此处就不需要将第二重循环设置为 \(V→v_i\),而是设为 \(V→0\)。
关于多种状态的选取
由于一组物品的多个体积的选取过程中可能出现 \(V-v_i<0\) 的情况,所以需要在选取过程中判定这一点。为方便编码,笔者选择把这一步封装成自定义函数。
AC code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#define RI register int
using namespace std;
const int maxn=4e4+10;
typedef struct
{
int w,v,pre;
int nex[3];
}object;
typedef struct
{
int w,v;
}node;
typedef struct
{
int l,r;
}range;
object obj[maxn];
node e[maxn<<2];
range rg[maxn];
int n,m,cnt;
int f[maxn<<4];
inline void init(void);
inline int calc(int x,int v);
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> n >> m;n/=10;
for(RI i=1;i<=m;++i)
{
cin >> obj[i].v >> obj[i].w >> obj[i].pre;
obj[i].w*=obj[i].v;obj[i].v/=10;
if(obj[i].pre) obj[obj[i].pre].nex[++obj[obj[i].pre].nex[0]]=i;
}
init();
for(RI i=1;i<=m;++i)
if(rg[i].l && rg[i].r)
for(RI j=n;j>=0;--j)
f[j]=max(f[j],calc(i,j));
printf("%d",f[n]);
fclose(stdin);fclose(stdout);
return 0;
}
inline void init(void)
{
/*将一个主件及其附件拆为多个单独的物品 拆分出的物品继承主附件的权值与体积和*/
/*同时开空间存储当前主件及其附件所对应的物品下标*/
for(RI i=1;i<=m;++i)
if(obj[i].pre) continue;
else if(!obj[i].nex[0])
{
e[++cnt]=(node){obj[i].w,obj[i].v};
rg[i]=(range){cnt,cnt};
}
else if(obj[i].nex[0]==1)
{
e[++cnt]=(node){obj[i].w,obj[i].v};
e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w,obj[i].v+obj[obj[i].nex[1]].v};
rg[i]=(range){cnt-1,cnt};
}
else
{
e[++cnt]=(node){obj[i].w,obj[i].v};
e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w,obj[i].v+obj[obj[i].nex[1]].v};
e[++cnt]=(node){obj[i].w+obj[obj[i].nex[2]].w,obj[i].v+obj[obj[i].nex[2]].v};
e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w+obj[obj[i].nex[2]].w,obj[i].v+obj[obj[i].nex[1]].v+obj[obj[i].nex[2]].v};
rg[i]=(range){cnt-3,cnt};
}
return;
}
inline int calc(int x,int v)
{
RI ret=0;
for(RI i=rg[x].l;i<=rg[x].r;++i)
if(v>=e[i].v)/*考虑是否买得下当前的物品*/
ret=max(ret,f[v-e[i].v]+e[i].w);/*若买得下 就更新状态*/
return ret;
}
标签:洛谷,主件,题解,选取,物品,附件,obj,include,P1064
From: https://www.cnblogs.com/frkblog/p/16830238.html