背包问题主要是背模板,这里收录了一些模板
一些复杂的背包问题(如泛化物品)未收录
01背包问题:
无优化
for(int i=1;i<=n;i++) { for(int c=0;c<=m;c++) { f[i][c]=f[i-1][c]; if(c>=w[i]) f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]); } }
一维数组优化:
for(int i=1;i<=n;i++) { for(int c=m;c>=0;c--) { if(c>=w[i]) f[c]=max(f[c],f[c-w[i]]+v[i]); } }
更进一步的常数优化:
for(int i=1;i<=n;i++) { sumw+=w[i]; bound=max(m-sumw,w[i]); for(int c=m;c>=bound;c--) { if(c>=w[i]) f[c]=max(f[c],f[c-w[i]]+v[i]); } }
完全背包问题:
for(int i=1;i<=n;i++) { for(int c=0;c<=m;c++) { if(c>=w[i]) f[c]=max(f[c],f[c-w[i]]+v[i]); } }
多重背包问题:
for(int i=1;i<=n;i++) for(int j=m;j>=1;j--) for(int k=0;k<=c[i];k++) { if(dp[j]-k*s[i]<0) break; dp[j]=max(dp[j],dp[j-k*s[i]]+k*c[i]); }
其实三种背包的区别在于数量的多少
所谓的01背包就是只能取一次,而完全背包是可以去无数次,多重背包对于每一件物品的数量有一个限定,所以我们要加入一个特判
if(dp[j]-k*s[i]<0) break;
没有什么技巧可言,对于数组的建立也是取决于个人喜好
下面是几道背包的例题(版子)
http://ybt.ssoier.cn:8088/problem_show.php?pid=1267
这是01背包的版子
#include<iostream> #include<cstdio> #include<math.h> #include<algorithm> #include<cstring> using namespace std; const int maxm=201,maxn=31; int m,n; int w[maxn],c[maxn]; int dp[maxm]; int main() { cin>>m>>n; for(int i=1;i<=n;i++) cin>>w[i]>>c[i]; for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+c[i]); cout<<dp[m]; return 0; }
http://ybt.ssoier.cn:8088/problem_show.php?pid=1268
完全背包的版子
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define itn int using namespace std; int dp[10000],w[10000],c[10000]; itn n,m; int main() { cin>>m>>n; for(int i=1;i<=n;i++) { cin>>w[i]>>c[i]; } for(int i=1;i<=n;i++) for(itn j=w[i];j<=m;j++) dp[j]=max(dp[j],dp[j-w[i]]+c[i]); cout<<"max="<<dp[m]<<endl; return 0; }
http://ybt.ssoier.cn:8088/problem_show.php?pid=1269
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define itn int #define q 10000 using namespace std; int dp[q],c[q],w[q],v[q]; int n,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>w[i]>>c[i]>>v[i];//价格 价值 数量 for(int i=1;i<=n;i++) for(int j=m;j>=0;j--) for(itn k=0;k<=v[i];k++) {if(j-k*w[i]<0) break; dp[j]=max(dp[j],dp[j-k*w[i]]+k*c[i]); } cout<<dp[m]; return 0; }
http://ybt.ssoier.cn:8088/problem_show.php?pid=1270
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define itn int #define q 10000 using namespace std; itn f[q],w[q],c[q],v[q]; int main() { int m,n; cin>>m>>n; for(int i=1;i<=n;i++) cin>>w[i]>>c[i]>>v[i]; for(int i=1;i<=n;i++) {if(v[i]==0) { for(itn j=w[i];j<=m;j++) f[j]=max(f[j],f[j-w[i]]+c[i]); } else for(itn j=1;j<=v[i];j++) for(itn k=m;k>=w[i];k--) f[k]=max(f[k],f[k-w[i]]+c[i]); } cout<<f[m]; return 0; }
最后的混合背包意思是对于物品的拿取的数量还是有要求的,有的可以无限拿(完全背包) 有的只能拿一次(01背包)
还有的只能拿指定的数量(多重背包)
对于混合背包 我们只需要对于他的数量进行判断({if(v[i]==0)) 那么便是完全背包;else 便是01或是多重(BB一句对于01背包 我们可以看做是这些都是只能取一次的多重背包,所以他们是一类)