算法学习笔记----用动态规划解决钢管切割问题

(说明:由于CSDN的博客中不能添加下标等特殊符号,所以部分内容使用截图的形式)

通过对问题进行高度抽象,现在我们的问题,就是要递归地求解r n 的最大值,下面采用的是一种自顶向下的递归方法:

int p[] = {1, 5, 8, 9, 10, 17, 17, 20, 24, 30}; static inline int max(i, j) { return (i > j ? i : j); }int cut_mod(int *p, int n) { int i; int q; if (n == 0) { return 0; }q = -1; for (i = 0; i < n; ++i) { q = max(q, p[i] + cut_mod(p, n - i - 1)); }return q; }


int bottom_up_cut_mod(int *p, int n) { int i, j, q; int r[n + 1]; r[0] = 0; for (j = 1; j <= n; ++j) { q = -1; for (i = 1; i <= j; ++i) { q = max(q, p[i - 1] + r[j - i]); }r[j] = q; }return r[n]; }

实现中max()函数及p的定义参见cut_mod()的实现。这里对实现做一个说明:第一个循环计算的是来选择长度,长度为j;第二个循环是计算长度为j时的最优解。过程是这样的:当j为1时,也就是说此时长度为1,这时最优解q=max(-1,p[0]+r[0]),此时q=p[0],即长度为1英寸的钢条的售价;当j为2时,此时长度为2,这时最优解就要在i=1和i=2之间进行选择,而i=1时的值在第一次循环中已计算出来保存在r数组中,i=2时等于是不切割。所以每次循环计算到j时,依赖的j-1对应的最优解已经计算出来,不需要再重复计算。 bottom_up_cut_mod()的实现只是给出了最优解,但是并没有保存最优解方案,也就是如何来切割。下面给出的bottom_up_cut_rod()的扩展版本,它对长度为j的钢条不仅计算最大收益值r j,还保存最优解对应的第一段钢条的切割长度s j(也就是我们前边说到的左边一段的长度,这段是不再进行切割的):
int extend_bottom_up_cut_mod(int *p, int n, int *s) { int i, j, q; int r[n + 1]; r[0] = 0; for (j = 1; j <= n; ++j) { q = -1; for (i = 1; i <= j; ++i) { if (q < p[i - 1] + r[j - i]) { q = p[i - 1] + r[j - i]; s[j] = i; } }r[j] = q; }return r[n]; } static void print_cut_mod_solution(int n, int *s) { while (n) { printf("%d ", s[n]); n = n - s[n]; } }

    推荐阅读