01背包
Posted bxd123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了01背包相关的知识,希望对你有一定的参考价值。
1
初始化的细节问题
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
2.
多重背包可以分成n个 也可以用二进制来优化:
#include <bits/stdc++.h> using namespace std; struct E { int w; //体积 int v; //重量 } lis[2001]; int dp[101]; int main() { int T,n,m; int p,h,k; int i,j; int index,c; scanf("%d%d",&n,&m); //n表示容量,m表示种类 index = 0; //拆分后物品总数 for( i=1; i<=m; i++) { c = 1; scanf("%d%d%d",&p,&h,&k); //p表示价格,h表示重量,k表示大米袋数。 while( k-c>0) { k -= c; lis[++index].w = c*p; lis[index].v = c*h; c *= 2; } lis[++index].w = p*k; //补充不足指数的差值 lis[index].v = h*k; } for( i=0; i<=n; i++) dp[i]=0; for( i=1; i<=index; i++) //对拆分后的物品进行0-1背包 { for( j=n; j>=lis[i].w; j--) dp[j] = max( dp[j],dp[j-lis[i].w]+lis[i].v); } printf("%d ",dp[n]); return 0; }
3.
打印物品:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[10005]; bool path[105][10005]; int c[10005],w[10005]; int main() { int N,V; while (cin>>V>>N) { memset(path,0,sizeof(path)); memset(dp,0,sizeof(dp)); for (int i = 1;i <= N;++i) cin>>c[i]>>w[i]; for (int i = N;i >= 1;--i) { for (int j = V;j >= c[i];--j) { if (dp[j] < dp[j-c[i]]+w[i]) { dp[j] = dp[j-c[i]]+w[i]; path[i][j] = 1; } } } cout<<dp[V]<<endl; puts("-----------------------------------------"); for (int i = 1,j = V;i <= N&&j > 0;i++) { if (path[i][j]) { printf("%d ",i); j -= c[i]; } } puts(""); } return 0; }
大牛总结的非常好:
https://www.kancloud.cn/kancloud/pack/70133
以上是关于01背包的主要内容,如果未能解决你的问题,请参考以下文章
代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些01背包问题,你该了解这些 滚动数组 416. 分割等和子集