给定一个问题, 能够使用动态规划的方法解决的一个标志就是, 这个问题具有最优子结构(optimal substructure)。 我们可以认为, 能够使用DP算法的问题首先能够分解为子问题。 而且我们可以利用子问题的最优解去解决原始问题的解。 这当然需要我们在解决了子问题的时候, 设法对子问题的最优解存储起来。这就是所谓的DP ≈ recursion(递归) + memoirizaion(备忘)。

下面我们通过算法导论书上的cutting a rod 的例子来说明如何去使用DP算法。

一个rod 的长度是n, 对于不同长度的rod, 价格不同。 用Pi 代表长度为i 的rod 的价格(i = 1, 2, 3, ... n )。 价格表如下:

下在问题来了:

当给我们个长度为4 的 rod, 让我们选择一种切割方案,  使得我们得到的总的收益是最大的???

如上图, 箭头表示我们的选择, 要么切割, 要么不切两种可能。 所以总共有2^(4 - 1) = 8 种方案。 考虑到由于对称性导致的重复, 其实只有五(4 + 1)种方案, 如下:

方案                              收益

(4, 0)                        9

(1, 3)                        9

(2, 2)                         10

(1, 1, 2)                  7

(1, 1, 1, 1,)          4

显然, 上述最佳的切割方案是(2, 2), 收益为10。

上述采用的是brute-force 算法, 显然时间复杂度能够到达O(2^(n-1)), 到达指数了, 显然效果很差, 算法伪代码如下:

解释, 进入循环:

i = 1, 表示在第一个长度单位的rod 是否切下来做决策, q = max(q, p[1] + CUT-ROD(p, n - 1)), 接下来就涉及到对于i = 1 的递归调用。

i = 2, 同理,  q = max(q, p[2] + CUT-ROD(p, n - 2)), 意思是第一次切割位于距离头为单位2的距离, 接下来, 对右边的那段进行递归调用。

............

i = n, 这种情况表示不切割, 还需要比较前面所有的切割方案中收益最大的值(存储在q)中, 然后和 不切割的方案比较, 去最大值就是我们的最大的收益。

上述算法达到exponential asymptotic time。

所以为了将算法的时间复杂度降下来, 我们使用dynamic programming:

这个问题为什么能用DP算法呢???

首先, 因为这个问题具有optimal substructure。  举个例子, 假设我们计算第一次切割在(3, 1)的最佳切割方案, 此时3 可以继续切割下去, 但是如果我们已经知道3 的最佳切割方案的收益的话(当然, 解决完子问题的时候, 需要将解存储下来), 我们直接采用3的最佳值直接加上1 即可以得到(3, 1)的后序最佳切割方案得到的收益值了。 这就是所谓的optimal substructure。 而且能够通过recursive 求解。

所以, 有如下注意的地方:

记录B(i) 为长度为i 的rod 采用最佳切割得到的收益。 所谓的最佳切割就是使得收益达到最大的切割。

那么, 我们有如下公式(Vk 代表Pk):

例如, 对于L = 8 的rod , 最大值B(8)的计算如下:

(1, 7), (2, 6), (3, 5), (4, 4), (5, 3), (6, 2), (7, 1), (8, 0)中得到。 pair 对应的第二个为需要求解的最佳值。

所以计算方法如下。

dynianc programming 的 bottom-up 形式的算法如下:

每当计算一个自问题的最佳解, 我们存储到表格中:

依次类推下去, 最终我们到达B(8), 如下:

如下:

这样, 我们就解决了这个问题。

整个算法的步骤如下:

这样动态规划将时间复杂度从exponential time 降低到了polynomial time

算法的伪代码为:

程序如下:

#include <iostream>
#include <cstring>using namespace std;const int N = 1000;
int p[11];
int r[N], s[N];//initializer for prices and optimal solution
void init() {memset(r, -1, sizeof(r));r[0] = 0;p[0] = 0;p[1] = 1;p[2] = 5;p[3] = 8;p[4] = 9;p[5] = 10;p[6] = 17;p[7] = 17;p[8] = 20;p[9] = 24;p[10] = 30;
}//naive exponential solutionint cutRod(int n) {int q = 0;for(int i = 1; i <= n; i++) {q = max(q, p[i] + cutRod(n - i));}return q;
}//top-down solution
int topDownCutRod(int n) {if(r[n] != -1)return r[n];int q = 0;for(int i = 0; i <= n; i++) {q = max(q, p[i] + topDownCutRod(n - i));}return r[n];
}//bottom-up solution
int bottomUpCutRod(int n) {if(r[n] != -1)return r[n];for(int j = 0; j <= n; j++) {int q = 0;for(int i = 1; i <= j; i++) {q = max(q, p[i] + r[j - 1]);}r[j] = q;}return r[n];
}//bottom-up solution that maintains not only the best
//price but also the "required cut" for such solutionint extendedBottomUpCutRod(int n) {if(r[n] != -1)return r[n];for(int j = 1; j <= n; j++) {int q = 0;for(int i = 1; i <= j; i++) {if (q < p[i] + r[j - i]) {q = p[i] + r[j - i];s[j] = i;}}r[j] = q;}return r[n];
}//print the extended method's output
void printCutRodSol(int n) {do {cout << s[n] << " ";} while((n -= s[n]) > 0);
}
int main() {init();int n;cout << "please input the length of the rod: " << endl;cin >> n;cout << endl;
//    cout << cutRod(4) << endl;
//    cout << cutRod(4) << endl;cout << extendedBottomUpCutRod(n) << endl;printCutRodSol(n);return 0;
}

运行结果如下:

DP 算法: cutting a rod相关推荐

  1. 算法题:Rod Cutting

    算法题:Rod Cutting 一.题目 二.代码 三.结果 一.题目 二.代码 lengths = [1,1,3,4] lengths = [5,4,4,2,2,8]def rodOffcut(le ...

  2. Cutting a Rod

    参考Top 20 Dynamic Programming Interview Questions. Cutting a Rod 题目:给定一根长度为n的木棒,同时有一个木棒长度从1到n对应的价格表,即 ...

  3. boost::geometry模块多边形DP算法简化示例

    boost::geometry模块多边形DP算法简化示例 实现功能 C++实现代码 实现功能 boost::geometry模块多边形DP算法简化示例 C++实现代码 #include <boo ...

  4. dp笔记:关于DP算法和滚动数组优化的思考

    从网上总结了一些dp的套路以及对滚动数组的一些思考,现记录如下,希望以后回顾此类算法时会有所帮助. 目录 1.DP算法经验 1.DP算法核心: 2.DP算法类别以及例题 例1:三步问题 例2:最小路径 ...

  5. Leetcode 64. 最小路径和 -- DP算法

    Time: 20190831 题目描述 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入: ...

  6. AIS数据压缩-改进的DP算法(Improved DP algorithm)

    在上两篇博客中,对AIS数据进行压缩用了两种方法: 1.AIS数据压缩-时间比率算法(Time-Ratio-algorithm) 2.AIS数据压缩-时间比率_速度_航向算法(Time-Speed-H ...

  7. 灰度图像压缩 DP算法 位运算详解

    作者码字不易,白天敲代码,晚上熬夜赶报告,要转载请注明出处哦,程序猿的辛酸泪 目录 位运算回顾 压缩过程 解压过程 关于一个莫得感情的小bug 实用小工具的下载地址 完整版代码 位运算回顾 若 a = ...

  8. 第十四周DP算法总结

    这周自己主要再看DP算法的博客,感觉DP这一部分内容确实比之前的都要麻烦一些,最后攻克这一部分难题还是挺好的. 这周自己总结了一些题型,以及一些方法思路,最后再把动态规划和之前的分治和贪心做一下比较. ...

  9. 模式识别读书报告---关于DP算法的…

    我喜欢玩星际争霸,当我操作我的部队用快捷键A进攻敌人时,部队就会自动避开障碍物attack目标.当时我就对为什么部队能自动选择最短的路进攻产生了兴趣,它是用什么算法实现的.而且当你的对手是电脑时,是用 ...

最新文章

  1. AI一分钟|FF联合创始人聂天心离职;Siri联合创始人从苹果离职
  2. 荐读 | 9篇近期社会化推荐论文
  3. Maven中jar版本冲突问题的解决
  4. c#命名法 【转】
  5. Win2003下Exchange2003部署图解之二
  6. 分布式Session解决方案_Spring Session + Redis
  7. -le: unary operator expected_【AFM+STM-LE】超经典:研究单分子化学反应引起的光发射ACS Nano...
  8. 为什么我们应该像盖房子那样写程序?
  9. async/await实现同步
  10. android adb工具命令大全
  11. 4种Dolby声场技术的区别
  12. 基于python的论文摘要怎么写_Python实现文章摘要的提取方式
  13. C语言,利用条件语句进行身高预测
  14. 集成学习【三】:Bagging结合神经网络及代码实现
  15. @Cacheable注解属性介绍
  16. P2608 [ZJOI2010]任务安排
  17. 一名理想主义的程序员
  18. 网站变灰,首页变灰怎么实现?
  19. html5播放器插件手机版,Html5弹幕视频播放器插件
  20. 住房月租金预测大数据赛

热门文章

  1. iphone6实际屏幕大小_5个最佳免费iPhone游戏(实际上是免费的)
  2. 2022年辽宁最新建筑八大员(材料员)模拟考试试题及答案
  3. Oracle Golden Gate 配置
  4. 如何根据普通ip地址获取当前地理位置
  5. fread()和readfile()fread()区别
  6. //排序案例//按照年龄进行升序,年龄相同按照身高降序
  7. Media wiki 搭建
  8. Jms_guacamole、Jms_koko 常见问题 修复
  9. 使用VScode写Python最后一行出现黄色下划线问题
  10. IAM -首个区块链信用操作系统白皮书V1.0