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

(说明:由于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];
    }
}

你可能感兴趣的:(算法学习笔记)