算法竞赛模板 动态规划之背包DP
① 01背包
有n件物品和一个容量为v的背包。第i件物品的价值是c[i],体积是w[i]。求解将哪些物品装入背包可使价值总和最大。
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
#include<bits/stdc++.h> using namespace std; int main() { int t,n,v,i,j,w[1005],c[1005],dp[1005]; cin>>t; while(t--) { memset(dp,0,sizeof dp); cin>>n>>v; for(i=1;i<=n;i++) scanf("%d",&c[i]); for(i=1;i<=n;i++) scanf("%d",&w[i]);
for(i=1;i<=n;i++) for(j=v;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+c[i]); cout<<dp[v]<<endl; } return 0; }
② 完全背包
有n种物品和一个容量为v的背包,每种物品都有无限件。第i种物品的价值是c[i],体积是w[i]。
#include<bits/stdc++.h> using namespace std; int main() { int t,n,v,i,j,w[1005],c[1005],dp[1005]; cin>>t; while(t--) { memset(dp,0,sizeof dp); cin>>n>>v; for(i=1;i<=n;i++) scanf("%d",&c[i]); for(i=1;i<=n;i++) scanf("%d",&w[i]); for(i=1;i<=n;i++) for(j=w[i];j<=v;j++) dp[j]=max(dp[j],dp[j-w[i]]+c[i]); cout<<dp[v]<<endl; } return 0; }
③ 多重背包
(1) 有n种物品和一个容量为v的背包。第i种物品最多有num[i]件,每件价值是c[i],体积是w[i]。
#include<bits/stdc++.h> using namespace std; int main() { int t,v,n,i,j,k,dp[105],num[105],c[105],w[105]; cin>>t; while(t--) { memset(dp,0,sizeof dp); cin>>n>>v; for(i=1;i<=n;i++) scanf("%d%d%d",&c[i],&w[i],&num[i]); for(i=1;i<=n;i++) for(j=1;j<=num[i];j++) for(k=v;k>=w[i];k--) dp[k]=max(dp[k],dp[k-w[i]]+c[i]); cout<<dp[v]<<endl; } return 0; }
(2) 2个人平分n种物品,第i种物品最多有num[i]件,每件物品价值为c[i],保证两者拥有物品的价值差距最小。
ps:物品总价值÷2,再去做多重背包。
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define MAX 100005 using namespace std; int dp[MAX],c[MAX],num[MAX]; int main() { int i,j,k,n,v,vhalf; while(scanf("%d",&n)!=EOF) { memset(dp,0,sizeof(dp)); v=0; for(i=1;i<=n;i++) { scanf("%d%d",&c[i],&num[i]); v+=c[i]*num[i]; //所有物品的总价值 } vhalf=v/2; for(i=1;i<=n;i++) for(j=1;j<=num[i];j++) for(k=vhalf;k>=c[i];k--) dp[k]=max(dp[k],dp[k-c[i]]+c[i]); cout<<v-dp[vhalf]<<" "<<dp[vhalf]<<endl; } return 0; }
④ 多重背包二进制优化
有n种船只,每种船只的载货量为w[i],每种船只的数量为2^c[i]-1。接下来有q次询问,每次问有多少种载货方式可以填满容量s,结果取模。
#include<bits/stdc++.h> using namespace std; const int MAX=1e4; const int mod=1e9+7; typedef long long ll; int w[25],c[25]; ll dp[MAX+5]; int main() { int n,i,T,q,s,j,k; ios::sync_with_stdio(false); cin>>T; while(T--) { cin>>n>>q; for(i=1;i<=n;i++) cin>>w[i]>>c[i]; memset(dp,0,sizeof(dp)); dp[0]=1; for(i=1;i<=n;i++) //共n种船 { int t=1; for(j=1;j<=c[i];j++)//每种船有2^c[i]-1只 { for(k=MAX;k>=t*w[i];k--) dp[k]=(dp[k]+dp[k-t*w[i]])%mod; t<<=1; } } while(q--) { cin>>s; cout<<dp[s]<<endl; } } return 0; }