动态规划(DP)通过分解成子问题解决了给定复杂的问题,并存储子问题的结果,以避免再次计算相同的结果。我们通过下面这个问题来说明这两个重要属性:
1)重叠子问题
2)最优子结构
1)重叠子问题:
像分而治之,动态规划也把问题分解为子问题。动态规划主要用于:当相同的子问题的解决方案被重复利用。在动态规划中,子问题解决方案被存储在一个表中,以便这些不必重新计算。因此,如果这个问题是没有共同的(重叠)子问题, 动态规划是没有用的。例如,二分查找不具有共同的子问题。下面是一个斐波那契函数的递归函数,有些子问题被调用了很多次。
1 |
/* simple recursive program for Fibonacci numbers */ |
2 |
int fib( int n)
|
3 |
{ |
4 |
if ( n <= 1 )
|
5 |
return n;
|
6 |
return fib(n-1) + fib(n-2);
|
7 |
} |
执行 fib(5) 的递归树
1 |
fib(5)
|
2 |
/ \
|
3 |
fib(4) fib(3)
|
4 |
/ \ / \
|
5 |
fib(3) fib(2) fib(2) fib(1)
|
6 |
/ \ / \ / \
|
7 |
fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)
|
8 |
/ \
|
9 |
fib(1) fib(0) |
我们可以看到,函数f(3)被称执行2次。如果我们将存储f(3)的值,然后避免再次计算的话,我们会重新使用旧的存储值。有以下两种不同的方式来存储这些值,以便这些值可以被重复使用。
A)记忆化(自上而下):
B)打表(自下而上):
一)记忆化(自上而下):记忆化存储其实是对递归程序小的修改,作为真正的DP程序的过渡。我们初始化一个数组中查找所有初始值为零。每当我们需要解决一个子问题,我们先来看看这个数组(查找表)是否有答案。如果预先计算的值是有那么我们就返回该值,否则,我们计算该值并把结果在数组(查找表),以便它可以在以后重复使用。
下面是记忆化存储程序:
01 |
/* Memoized version for nth Fibonacci number */ |
02 |
#include<stdio.h> |
03 |
#define NIL -1 |
04 |
#define MAX 100 |
05 |
06 |
int lookup[MAX];
|
07 |
08 |
/* Function to initialize NIL values in lookup table */ |
09 |
void _initialize()
|
10 |
{ |
11 |
int i;
|
12 |
for (i = 0; i < MAX; i++)
|
13 |
lookup[i] = NIL;
|
14 |
} |
15 |
16 |
/* function for nth Fibonacci number */ |
17 |
int fib( int n)
|
18 |
{ |
19 |
if (lookup[n] == NIL)
|
20 |
{
|
21 |
if ( n <= 1 )
|
22 |
lookup[n] = n;
|
23 |
else
|
24 |
lookup[n] = fib(n-1) + fib(n-2);
|
25 |
}
|
26 |
27 |
return lookup[n];
|
28 |
} |
29 |
30 |
int main ()
|
31 |
{ |
32 |
int n = 40;
|
33 |
_initialize();
|
34 |
printf ( "Fibonacci number is %d " , fib(n));
|
35 |
getchar ();
|
36 |
return 0;
|
37 |
} |
一)打表(自下而上)
下面我们给出自下而上的打表方式,并返回表中的最后一项。
01 |
/* tabulated version */ |
02 |
#include<stdio.h> |
03 |
int fib( int n)
|
04 |
{ |
05 |
int f[n+1];
|
06 |
int i;
|
07 |
f[0] = 0; f[1] = 1;
|
08 |
for (i = 2; i <= n; i++)
|
09 |
f[i] = f[i-1] + f[i-2];
|
10 |
11 |
return f[n];
|
12 |
} |
13 |
14 |
int main ()
|
15 |
{ |
16 |
int n = 9;
|
17 |
printf ( "Fibonacci number is %d " , fib(n));
|
18 |
getchar ();
|
19 |
return 0;
|
20 |
} |
这两种方法都能存储子问题解决方案。在第一个版本中,记忆化存储只在查找表存储需要的答案。而第二个版本,所有子问题都会被存储到查找表中,不管是否是必须的。比如LCS问题的记忆化存储版本,并不会存储不必要的子问题答案。
ACM之家原创,文章链接:http://www.acmerblog.com/dynamic-programming-4577.html
相关推荐
在讲动态规划课时,我们知道可用动态规划算法求解的问题应具备的一个基本要素是子问题的重叠性质,矩阵连乘问题能用动态规划求解正是因为它具有重叠子问题。因此在解矩阵连乘问题的自顶向下的递归算法中,存在着大量...
第四章动态规划2020年10月26日星期一学习要点理解动态规划算法的概念。掌握动态规划算法的基本要素(1)最优子结构性质(2)重叠子问题理解动态规划算法与贪心算
应用动态规划算法的最优子结构性质和子问题重叠性质求解此问题。分析动态规划算法的基本思想,应用动态规划策略写出算法及相应的程序,求解此题。要读懂读透A[i,j],A[1,n]=A[1,k] ×A[k+1,n],m[i][j],s[i][j]各式...
应用动态规划算法的最优子结构性质和子问题重叠性质求解此问题。分析动态规划算法的基本思想,应用动态规划策略写出算法及相应的程序,求解此题。要读懂读透A[i,j],A[1,n]=A[1,k] ×A[k+1,n],m[i][j],s[i][j]各式...
2、重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中...
《动态规划》之--字符串比较问题(扩展距离),主要思路通过策略和无效性来求解。特点最优子结构性质,重叠子问题。
动态规划常常适用于有重叠子问题和最优子结构性质的问题。 动态规划的基本思想是将待求解的问题分解成若干个相互重叠的子问题,并自底向上地求解这些子问题,最终子问题的解被组合起来,形成原问题的解。动态规划...
(2)重叠子问题性质 掌握设计动态规划算法的步骤。 (1)找出最优解的性质,并刻划其结构特征。 (2)递归地定义最优值。 (3)以自底向上的方式计算出最优值。 (4)根据计算最优值时得到的信息,构造最优解。 学习要点: ...
首先对0-1背包问题进行了描述,根据其具有最优子结构性质和子问题重叠性质,进而提出了基于动态规划法的策略来求解该问题。另外,为了降低算法的复杂性,又提出了算法的改进策略。实例的运行结果表明了算法的有效性,同时...
01背包问题解决方法不少,动态规划是其中之一,动态规划的问题解题思路都差不多(一些浅见),基本要素是最优子结构性质,子问题重叠性质,自底向上的求解方法。只要了解了基本要素,那么这种题型也会更好理解。本题...
第7章 动态规划法学习要点:理解动态规划算法的概念。掌握动态规划算法的基本要素(1)最优子结构性质(2)重叠子问题性质掌握设计动态规划算法的步骤。理解动态规划算
动态规划算法的有效性依赖于待求解问题本身具有的两个重要性质:最优子结构性质和子问题重叠性质。 1、最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最...
由最长公共子序列问题的最优子结构性质可知,要找出X=, x2, …, xm>和Y=, y2, …, yn>的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的...
最优子结构性质和子问题的重叠性质、 基本步骤 (4 步); 多段图问题、0/1 背包问题 * 、矩阵连乘积问题、最短路径 问题、最长公共子序列问题 ** ; 所有上述问题的最优子结构性质、算法的基本步骤。
1、理解动态规划的基本思想,理解动态规划算法的两个基本要素最优子结构性质和子问题的重叠性质。 2、熟练掌握典型的动态规划问题。 3、掌握动态规划思想分析问题的一般方法,对较简单的问题能正确分析,设计出动态...
动态规划通常用于解决那些具有重叠子问题和最优子结构性质的问题。它的优点在于能够保证得到全局最优解,并且可以通过记忆化搜索或者自底向上的方法有效地进行求解。但是动态规划算法的缺点在于可能会消耗较多的内存...
动态规划问题,基本要素是最优子结构性质,子问题重叠性质,自底向上的求解方法。只要了解了基本要素,那么这种题型也会更好理解。本题有不少注释,便于读者阅读。
由于动态规划算法解决问题往往有重叠子问题的特点,因此为了减少重复计算,不管该子问题以后是否被用到,只要它被计算过,就将其结果填到表中。动态规划算法适用于解最优化问题,通常可按照四个步骤进行设计: ①找...
主要介绍了用Python展示动态规则法用以解决重叠子问题的一个棋盘游戏的示例,动态规划常常适用于有重叠子问题和最优子结构性质的问题,且耗时间往往远少于朴素解法,需要的朋友可以参考下
LCS问题具有最优子结构和重叠子问题的性质,因此采用动态规划算法自底向上计算该问题的解,并输出求到的LCS。