dp入门与两个基础的背包问题
来源:互联网 发布:网络有重名怎么恢复 编辑:程序博客网 时间:2024/06/11 18:57
引子:
第一个问题:现在有3种硬币,1角钱,2角钱,3角钱,那么问题来了凑出n角钱最少需要多少硬币。
这个问题可以用贪心法解决。如果n比3大,那么一直取3就好了。最后少的要么是2,要么是1,所以答案是n/3+(n%3)?1:0;
第二个问题:现在有3种硬币,2角钱,3角钱,5角钱,那么问题来了凑出n角钱最少需要多少硬币。
如果n为16的话,一直取5那么最后剩1,就就不行了。
这时候就要用到动态规划。
01背包
01背包问题描述:现在有n个物品,人现在有一个容量为m的背包,每个物品有价值vi和重量wi,那么问题来了,在总重量不超过m的情况下使得价值最大,请问该怎么选?
这是最基础的问题,特点是对于每一种物体仅有一个,只存在放或者不放两种情况。
我们设p[i][j]表示前i个物体放入一个容量为j的背包时的最大价值。那么对于p[i-1]来说,我们可以看出就是一个取第i个和不取第i个的区别。那么就可以列出式子
p[i][j]=max( p[i-1][j] , p[i-1][j-w[i]]+v[i] );
所以我们可以列出式子
for(int i=0;i<n;i++)
for(int j=m;j>=w[i];j--)
p[j]=max(p[i-1][j],p[i-1][j-w[i]]+v[i]);
至于为什么第二重循环要从m循环到w[i]呢,其实在这里从m到w[i]或者从w[i]到m是无所谓的。
但是,如果只用一维数组来存结果,那么第二重循环就必须从m减到w[i]了。因为一维数组默认用到的前一个p[i-1][j]的值,我们必须保证用到的是上一层循环留下来的数据而不是这个i值留下来的新的数据。
for(int i=0;i<n;i++)
for(int j=m;j>=w[i];j--)
p[j]=max([j],p[j-w[i]]+v[i]);
是不是简单多了?
完全背包
完全背包问题是另外一种背包问题,还是原来的m,w[i],v[i],但是这时候每种可以取无数多个。
那么最直接的想法,f[i-1][j]=max{ f[i-1][v-k*v[i]]+k*w[i] },0<k<m/w[i]
然而这个算法复杂度是O(n^3)的,太恐怖了,简直不堪入目,不到万不得已不能用的。
那么怎么办呢?对于f[i-1][j]来说,再用取或者不取的思路来说,应该是f[i][j]=max(f[i-1][j],f[i][j-w[i]]+v[i])
这时候我们可以想一想,上面01背包的第二重循环为什么要从m到w[i],就是为了保证每种只取一次。现在既然每种可以取无限次,那么就没必要从m开始循环了,从0开始恰好就满足了完全背包的条件。
for(int i=0;i<n;i++)
for(int j=v[i];j<=v;j++)
dp[j]=max(dp[j-1],dp[j-v[i]]+w[i]);
那么dp[n][m]就是答案了。
- dp入门与两个基础的背包问题
- Dp基础 简单背包问题
- 入门经典 DP 0-1背包问题
- hdu-1561 The more, The Better (树形dp入门,有依赖的背包问题
- DP背包基础
- DP入门, 0-1背包问题(HDOJ 2602类似)
- HDU 2546 饭卡 【入门DP之01背包问题】
- DP 背包问题 01背包
- XMU-1028(典型的背包问题(dp))
- 解决01背包问题的DP方法
- dp 背包问题01的优化
- 【算法设计与分析基础】背包问题
- 51nod-正整数分组问题(基础方程DP-01背包)
- DP背包问题
- DP【背包问题】
- DP&背包问题
- dp之背包问题
- DP优化--背包问题
- 《一》将关注订阅号用户的基本信息入库
- 我如何让软件二次开发变简单
- 使用jdcloud-wui筋斗云前端框架如何快速定位到源码
- Android studio 制作.9图片步骤
- 使用BadBoy录制JMeter脚本
- dp入门与两个基础的背包问题
- jquery ajax
- Redis做消息队列文章两篇
- Spark Shuffle之Sort Shuffle
- tableView局部刷新
- Linux下磁盘分区和目录的关系
- 重映射、仿射变换、直方图均衡化
- Android App框架设计 基类BaseActivity
- 等保-国家标准化管理委员会批准18项信息安全技术国家标准