完全背包
来源:互联网 发布:女鞋原单淘宝推荐 编辑:程序博客网 时间:2024/06/02 23:53
有n个物品,每个物品体积是costs = {c1,c2,...cn},每个物品的价值是values = {v1,v2,...vn},每个物品只能取无限次。现在有体积为v的背包,问将这些物品放入该背包,能得到的最大价值是多少?并输出最大时的选择方案。
推导:设dp[i][j]为将前i个物品放入体积为j的背包时取得的最大价值。来看,dp[i][j]可由哪些状态得到?
1、若第i个物品不放入背包,那么dp[i][j] = dp[i - 1][j];
2、若第i个物品放入背包,那么此时dp[i][j]不能再像01背包那样子等于dp[i - 1][j - costs[i]] + values[i]了,因为dp[i - 1][k]前i - 1个物品,可现在的要求是每个物品都可以放无数次。那么,就应该是dp[i][j] = dp[i][j - costs[i]] + values[i],表示dp[i][j]是由当前i状态得来的而不是由它的前一个状态i - 1得来的。
那么完全背包的状态方程就应该是:dp[i][j] = max(dp[i - 1][j],dp[i][j - costs[i]] + values[i])(i = 0 或者j = 0时dp[i][j] = 0),由此可写出代码:
for(int i = 1;i <= n;i++)for(int j = 0;j <= v;v++)if(j < costs[i])dp[i][j] = dp[i - 1][j];elsedp[i][j] = max(dp[i - 1][j],dp[i][j - costs[i]] + values[i]);由此可看出完全背包的时间复杂度为O(nv),空间复杂度为O(nv)。同01背包一样,我们同样可以用滚动数组将其空间复杂度降为O(v)。
for(int i = 1;i <= n;i++)for(int j = costs[i];j <= v;j++)dp[j] = max(dp[j],dp[j - costs[i]] + values[i]);可以看到,区01背包的区别只是内层循环变为顺序了。关于利用滚动数组来降低空间复杂度,只要在纸上画下就清楚了。
我们再来看如何记录路径。我们用path[i][j] = (x,y)表示从(x,y)到(i,j)有条路径,那么i != x的时候说明第i个物品没有放进背包。
#define N 1001struct CompletePack{/* *numOfres:物品的个数 *volumeOfpack:背包容量 *path:记录路径 *costs[i]:第i个物品的消耗 *values[i]:第i个物品的价值 *求放进容量为volumeOfpack的背包能取得的最大价值 */int dp[N];int path[N][N][2];int costs[N],values[N],numOfres,volumeOfpack;CompletePack(int numOfres,int volumeOfpack,int costs[],int values[]){this->numOfres = numOfres;this->volumeOfpack = volumeOfpack;for(int i = 1;i <= this->numOfres;i++)this->costs[i] = costs[i],this->values[i] = values[i];memset(dp,0,sizeof(dp));memset(path,0,sizeof(path));}int getMaxValue(){for(int i = 1;i <= numOfres;i++){int j;for(j = 0;j < costs[i];j++)path[i][j][0] = i - 1,path[i][j][1] = j;for(;j <= volumeOfpack;j++){int tmp = dp[j - costs[i]] + values[i];if(dp[j] < tmp){dp[j] = tmp;path[i][j][0] = i,path[i][j][1] = j - costs[i];}elsepath[i][j][0] = i - 1,path[i][j][1] = j;}}return dp[volumeOfpack];}/* * 输出路径,path[i][j] = (x,y),表示从(x,y)到(i,j)有一条路径,当path[i][j] = (i - 1,j)时表示第i个物品没有放入背包 * 初始参数为(numOfres,volumeOfpack) */void getPath(int i,int j){if(!i || !j)return;if(path[i][j][0] == i - 1){getPath(i - 1,j);return;}int num = 0;//记录第i个物品放入背包的个数while(path[i][j][0] == i){num++;j = path[i][j][1];}getPath(i,j);//values[i]*numprintf("values[%d]:%d*%d ",i,values[i],num);}};
题目:
1、hdu 1248 模板题
2、hdu 1114 求刚好能放满v的背包时的最小价值。初始化时dp[0] = 0,其它为INF,表示不合法。
3、hdu 1284 完全背包求排列组合的总方案数。设dp[i][j]为前i个物品能组成容量j的方案数,那么dp[i][j] = dp[i - 1][j] + dp[i][j - costs[i]]。
4、poj 3181 同1284一样,也是求方案数。不过这题结果超过了long long,要用到大数相加。
5、hdu 2159 二维完全背包。用dp[i][j]表示用i的忍耐值和杀j只怪能得到的最大经验值。因为题目要求求能升级的消耗最少的忍耐值的方案,故最后遍历dp数组找个最优值就OK了。
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包!!
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 完全背包
- 一分钟内掌握较复杂sql
- 在用Android WebView调用js时方法错误
- TOJ 1837 HDU 1385 ZOJ 1456 Minimum Transport Cost / 最短路径
- 自定义UIActionSheet
- 如何做好配置管理 配置管理的三大误区
- 完全背包
- python错误和异常(1)
- MFC CWnd仿按钮
- CSharp tar类型文件压缩与解压
- PHP 重建数组函数 array_values
- html5 笔记4 地理定位(Geolocation)
- JAVADBF操作
- wordpress 使用固定链接
- How to detect screenshots on iOS (like SnapChat)