P1064 金明的预算方案
传送门
思路:
有条件的 01背包(有依赖的背包)。
可分为四种情况来做 01背包 :①不买主件 ②买主件 ③买主件+副件1 ④买主件+副件2 ⑤买主件+副件1+副件2
转移条件:
①没有附件,按最基本的 01背包来做。
②该附件和主件的重量(为区分价格和价值,接下来的所有分析都按背包理解)之和 ≤ 现在在判断的 j (背包剩余容量)(也是按照 01背包 的模板做)
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<queue> #include<vector> #include<deque> #include<stack> #include<map> #include<set> using namespace std; #define maxn 40000 int m,n,v,p,q;//m背包容量,n物品数量,v物品价格,p重要程度,q判断是否为主件 int mw[maxn],mv[maxn],fw[maxn][3],fv[maxn][3]; //mw主件重量,mv主件价值,fw主件对应的附件重量,fv主副价值,n总重量,m总个数 int f[maxn]; inline int read() { int kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return kr*xs; } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { v=read();p=read();q=read(); if(!q)//如果是主件 { mw[i]=v;//主件重量 mv[i]=v*p;//主件价值与重量乘积 } else//如果是附件 { fw[q][0]++;//记录主件的附件个数(只记录在fw就行,fv那里没用 fw[q][fw[q][0]]=v;//主件的个数是用来确定该附件应该填在第一个还是第二个格子里 fv[q][fw[q][0]]=v*p;//(是第一个还是第二个附件) } } for(int i=1;i<=m;i++) for(int j=n;j>=mw[i];j--)//01背包模板 { //每一个if的前提是背包能不能装下该物品 f[j]=max(f[j],f[j-mw[i]]+mv[i]);//情况1:只要主件和什么都不要比较 if(j>=mw[i]+fw[i][1])//情况2:主件和附件1 和上面选出的较大值比较 f[j]=max(f[j],f[j-mw[i]-fw[i][1]]+mv[i]+fv[i][1]); if(j>=mw[i]+fw[i][2]) //情况3:主件和附件2 和上面选出的较大值比较 f[j]=max(f[j],f[j-mw[i]-fw[i][2]]+mv[i]+fv[i][2]); if(j>=mw[i]+fw[i][1]+fw[i][2])//情况4:都要 f[j]=max(f[j],f[j-mw[i]-fw[i][1]-fw[i][2]]+mv[i]+fv[i][1]+fv[i][2]); } printf("%d\n",f[n]);//输出 return 0; }