您的位置:首页 > 编程语言 > C语言/C++

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

2015-08-03 17:05 447 查看

动态规划

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

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

我们通常按如下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
>= 0)  return r
;
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
= 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
;
}


代码很简单,书上写得也很明白,斜杠行以上为第一种方法,以下为第二种方法。

书中其他问题不再描述。很直白简单,动态规划的核心 是对 子问题的构造 和对 公共子问题的解的重用。而动态两个字,想必是出于运行时的解释。

for more information,see Introduce to algorithm.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息