背包问题
#include<iostream> using namespace std; int a[210][210],b[210],c[40]; int max(int,int); int n,m,maxn; int main() { cin>>m>>n; for(int i=1;i<=n;i++) cin>>b[i]>>c[i]; for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++) { for(int k=0;k<=1;k++) { a[i][j]=a[i-1][j]; if(j>=b[i]*k) a[i][j]=max(a[i][j],a[i-1][j-k*b[i]]+c[i]*k); } } } cout<<"max="<<a[n][m]; return 0; } int max(int x,int y) { if(x>y) return x; else return y; }
这是最简单的一种背包问题的最简单的实现方式
二维数组好理解但是太浪费空间了,很容易让数据范围太小或空间超限,总之就是很烦
#include<iostream> using namespace std; int a[100000]; int n,wi,ci,w; int main() { cin>>w>>n; for(int i=1;i<=n;i++) { cin>>wi>>ci; for(int j=w;j>=wi;j--) { a[j]=max(a[j],ci+a[j-wi]); } } cout<<a[w]; return 0; }
这是一维数组的实现,但是一定要记住:j是从w倒着循环到wi的
然后就是01背包求方案数
#include<iostream> using namespace std; int a[100000],b[100000]; int n,wi,ci,w; int main() { cin>>n>>w; a[0]=1; for(int i=1;i<=n;i++) cin>>b[i]; for(int i=1;i<=n;i++) { for(int j=w;j>=b[i];j--) { a[j]=a[j]+a[j-b[i]]; } } cout<<a[w]; return 0; }
每次都有选与不选两种决策,只需要加起来就好了
(其实我也没太看懂
完全背包:
#include<iostream> using namespace std; int a[100000]; int n,wi,ci,w; int main() { cin>>w>>n; for(int i=1;i<=n;i++) { cin>>wi>>ci; for(int j=wi;j<=w;j++) { a[j]=max(a[j],ci+a[j-wi]); } } cout<<"max="<<a[w]; return 0; }
比较懒,就不上二维数组了(反正也没耐心看
二维数组求方案数:
#include<iostream> using namespace std; int a[100000],b[100000]; int n,wi,ci,w; int main() { cin>>n>>w; a[0]=1; for(int i=1;i<=n;i++) cin>>b[i]; for(int i=1;i<=n;i++) { for(int j=b[i];j<=w;j++) { a[j]=a[j]+a[j-b[i]]; } } cout<<a[w]; return 0; }
多重循环:
#include<iostream> using namespace std; int f[200000],n,b[100000],c[100000],v,d[100000]; int max(int x,int y) { if(x>y) return x; else return y; } int main() { cin>>n>>v; for(int i=1;i<=n;i++) { cin>>b[i]>>c[i]>>d[i]; // if(d[i]==0) d[i]=v; } for(int i=1;i<=n;i++) { for(int j=v;j>=b[i];j--) { for(int k=0;k<=d[i];k++) if(j>=k*b[i]) f[j]=max(f[j],f[j-b[i]*k]+c[i]*k); } } cout<<f[v]; return 0; }
然后多重背包的方案数和完全背包的方案数一样
ps:强调几个重点吧
1.用动态数组的时候一定要倒着循环,很重要
2.如果一定要用二维数组实现的话别忘了状态转移方程里01背包是i-1,完全背包是i本身,很蠢但是我错了好几次