Introduce to algorithm--------pseudo code to C/C++ code(chapter 15)

动态规划

就像算法导论中说的那样,动态规划与分治算法相似,是通过组合子问题的方法求解原问题。分治将原问题划分为互不相交的子问题,递归求解,然后再将子问题组合起来,求出原问题的解。而动态规划用于子问题重叠的情况,不同的问题会有公共的子问题,在这种情况下,可以重用第一次求解的公共子问题的解,省去很多不必要的计算。

动态规划常用来求解最优化问题

我们通常按如下4个来设计一个动态规划算法:

1.刻画一个最优解的结构特征。

2.递归的定义最优解的值。

3.计算最优解的值,通常采用自底向上的方法。

4.利用计算出的信息构造一个最优解。

钢条切割问题

将一条固定长度的钢条切割成不同的长度,每种长度的价格不同且固定,求切割后总价格最高的最优切割方案。
传统的递归求解方案会使代码的时间复杂度变得很高。伪代码如下:

CUT_ROD (p,n)
{
    if n == 0
        return 0
    q = -∞;
    for i= 1 to n
        q = max (q,p[i] + CUT_ROD (p, n - 1))
    return q
}

显而易见,函数的核心部分是自递归。也正是因为简单的自递归,导致在n变量较大的情况下,函数的运行时间变得很长。动态规划的核心是对子问题的重用,所以该问题用动态规划来解是最适合不过。导论中有两种方法:

  • 带备忘的自顶向下法(top-down with memoization)
  • 自底向上法(bottom-up method)

带备忘的意思就是带记录,即将解记录下来的意思。两种方法的代码如下:

#include <stdio.h>
#include <math.h>

#define NEGATIVE_INFINITY   -1

int MEMOIZED_CUT_ROD_AUX (int* p, int n, int* r)
{
    int     q;

    if (r[n] >= 0)  return r[n];
    if (n == 0)     q =  0;
    else            
    {
        q = NEGATIVE_INFINITY;
        for (int i = 1; i <= n; ++i)
            q = max (q, p[i] + MEMOIZED_CUT_ROD_AUX (p, n - i, r));
    }
    r[n] = q;
    return q;
}

int MEMOIZED_CUT_ROD (int* p, int n)
{
    int*    r = static_cast<int*> (malloc (sizeof (int) * (n + 1)));
    for (int i = 0; i <= n; ++i)
        r[i] = NEGATIVE_INFINITY;
    return MEMOIZED_CUT_ROD_AUX (p, n, r);
}



int BOTTOM_UP_CUT_ROD (int* p, int n)
{
    int     q;
    int*    r = static_cast<int*> (malloc (sizeof (int) * (n + 1)));
    r[0] = 0;
    for (int j = 1; j <= n; ++j)
    {
        q = NEGATIVE_INFINITY;
        for (int i = 1; i <= j; ++i)
            q = max (q, p[i] + r[j - i]);
        r[j] = q;
    }
    return r[n];    
}

代码很简单,书上写得也很明白,斜杠行以上为第一种方法,以下为第二种方法。
书中其他问题不再描述。很直白简单,动态规划的核心 是对 子问题的构造 和对 公共子问题的解的重用。而动态两个字,想必是出于运行时的解释。

for more information,see Introduce to algorithm.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值