依赖性的01背包
康神是谁,那是相当的强,亲自给我讲这道金明的预算方案。看不懂书上代码的情况之下,正解:树形dp~不会。
康神把书上的思路给我讲了一遍。
于是知道了这道题要先拿主件01背包,再对附件做一个01背包,使每次拿附件的同时都跟上一个附件的价值,进行01背包,注意这个地方要开一个临时的数组a,a这里要考虑对f数组的更新,为什么不直接用f数组进行更新呢?这个是为了防止f数组里存的最优解丢失,因为你不知道要拿什么东西可以使f数组更新,这里可以更新f数组的状态过多,如果直接用f数组更新可能无法取到最优,所以这里用一个a数组表示必须选择当前物品,看看当前的物品加上它的附件是否可以更新f数组即可。
#include<iomanip> #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=32002; int q[66],a[maxn],f[maxn],w[66],v[66]; int n,m; int main() { // freopen("1.in","r",stdin); m=read();n=read(); for(int i=1;i<=n;i++) { w[i]=read();v[i]=read();q[i]=read(); v[i]=v[i]*w[i]; } for(int i=1;i<=n;i++) { if(q[i]==0) { for(int j=1;j<=w[i];j++)a[j]=0; for(int j=w[i];j<=m;j++)a[j]=f[j-w[i]]+v[i]; for(int j=1;j<=n;j++)if(q[j]==i) for(int k=m;k>=w[i]+w[j];k--)a[k]=max(a[k-w[j]]+v[j],a[k]); for(int j=1;j<=m;j++)f[j]=max(f[j],a[j]); } } printf("%d\n",f[m]); return 0; }
这样就可以得到最优解啦。
虽然正解是树形dp,可那是针对附件无限多的情况的,这里每个零件只有0个,1个,2个附件,所以考虑这里针对每一个主件直接使用01背包,状态转移分为4种情况:光是主件,主件加第一个1附件,主件加第二个附件,主件同时加第一个和第二个附件。4个状态转移方程跑一个选还是不选(核心其实就是一个分组背包)。
每一组01背包的倒叙循环即可寻找得到且重复只选一种物品且每种物品选的话就一定会有主件。
#include<iomanip> #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=32002; struct bwy//闻道玉门犹被遮,应将性命逐轻车 { int w,v,w1,v1,w2,v2,w3,v3; }t[66]; int f[maxn],n,m,len=0; int main() { //freopen("1.in","r",stdin); m=read();n=read(); for(int i=1;i<=n;i++) { int x,y,z; x=read();y=read();z=read(); if(z==0)t[i].w=x,t[i].v=x*y; else if(t[z].w1==0)t[z].w1=x+t[z].w,t[z].v1=x*y+t[z].v; else t[z].w2=x+t[z].w,t[z].v2=x*y+t[z].v; if(t[z].w2!=0){t[z].w3=t[z].w2+t[z].w1-t[z].w;t[z].v3=t[z].v2+t[z].v1-t[z].v;} } for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { if(j>=t[i].w)f[j]=max(f[j-t[i].w]+t[i].v,f[j]); if(j>=t[i].w1)f[j]=max(f[j-t[i].w1]+t[i].v1,f[j]); if(j>=t[i].w2)f[j]=max(f[j-t[i].w2]+t[i].v2,f[j]); if(j>=t[i].w3)f[j]=max(f[j-t[i].w3]+t[i].v3,f[j]); } } printf("%d\n",f[m]); return 0; }
茫茫碧落,天上人间情一诺。