E16 背包DP 分组背包
物品分为 k 组,每组内的物品相互冲突。
已知物品件数和背包容积,每件物品的体积,价值,所属组数。求最大价值。
分组记录物品个数、体积、价值。
依次枚举分组、体积、组内物品,类似 01 背包转移。
// 分组背包 O(nm) #include<bits/stdc++.h> using namespace std; const int N=1010; int n,m,cnt; int v[N][N],w[N][N],s[N]; //v[i,j]:第i组第j个物品的体积 s[i]:第i组物品的个数 int f[N][N]; //f[i,j]:前i组物品,能放入容量为j的背包的最大价值 int main(){ cin>>m>>n; //容积 物品 for(int i=1,a,b,c;i<=n;i++){ cin>>a>>b>>c; //体积 价值 所属分组 v[c][++s[c]]=a; w[c][s[c]]=b; cnt=max(cnt,c); } for(int i=1;i<=cnt;i++){ //分组 for(int j=m;j>=0;j--){ //体积 for(int k=0;k<=s[i];k++){ //组内物品 if(j>=v[i][k]) f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]); else f[i][j]=max(f[i-1][j],f[i][j]); } } } cout<<f[cnt][m]; }
// 分组背包+优化空间 O(nm) #include<bits/stdc++.h> using namespace std; const int N=1010; int n,m,cnt; int v[N][N],w[N][N],s[N]; //v[i,j]:第i组第j个物品的体积 s[i]:第i组物品的个数 int f[N]; //f[i,j]:前i组物品,能放入容量为j的背包的最大价值 int main(){ cin>>m>>n; //容积 物品 for(int i=1,a,b,c;i<=n;i++){ cin>>a>>b>>c; //体积 价值 所属分组 v[c][++s[c]]=a; w[c][s[c]]=b; cnt=max(cnt,c); } for(int i=1;i<=cnt;i++){ //分组 for(int j=m;j>=0;j--){ //体积 for(int k=0;k<=s[i];k++){ //组内个数 if(j>=v[i][k]) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]); } } } cout<<f[m]; }
P1064 [NOIP 2006 提高组] 金明的预算方案 - 洛谷
// 有依赖的背包 O(nm) #include<bits/stdc++.h> using namespace std; int n,m; int zv[65],zw[65],fv[65][3],fw[65][3]; int f[32005]; int main(){ cin>>m>>n; //m总钱数, n总个数 for(int i=1,v,p,q; i<=n; i++){ cin>>v>>p>>q; //价格 重要度 对应的主件 if(!q){ zv[i]=v; //主件价格 zw[i]=v*p; //主件价值 } else{ ++fv[q][0]; //附件个数 fv[q][fv[q][0]]=v; //fv附件价格 fw[q][fv[q][0]]=v*p; //fw附件价值 } } for(int i=1; i<=n; i++) if(zv[i]){ //如果第i个物品是主件 for(int j=m; j>=zv[i]; j--){ //价格 f[j]=max(f[j],f[j-zv[i]]+zw[i]); //只选主件 if(j>=zv[i]+fv[i][1]) //选主件+a f[j]=max(f[j],f[j-zv[i]-fv[i][1]]+zw[i]+fw[i][1]); if(j>=zv[i]+fv[i][2]) //选主件+b f[j]=max(f[j],f[j-zv[i]-fv[i][2]]+zw[i]+fw[i][2]); if(j>=zv[i]+fv[i][1]+fv[i][2]) //选主件+a+b f[j]=max(f[j],f[j-zv[i]-fv[i][1]-fv[i][2]]+zw[i]+fw[i][1]+fw[i][2]); } } cout<<f[m]; }
浙公网安备 33010602011771号