动态规划

  动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间。

  动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

  我们常常听到的动态规划思想就是:记忆,空间换时间, 不重复求解, 由交叠子问题从较小问题解逐步决策, 构成较大问题的解。

      斐波那契数列可以作为最简单的一个例子解释动态规划思想

      计算斐波那契数列(Fibonacci polynomial)的一个最基础的算法是,直接按照定义计算:

      

1  function fib(n)
2        if n = 0 or n = 1
3            return 1
4        return fib(n − 1) + fib(n − 2)

      

当n=5时,fib(5)的计算过程如下:

  1. fib(5)
  2. fib(4) + fib(3)
  3. (fib(3) + fib(2)) + (fib(2) + fib(1))
  4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
  5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

由上面可以看出,这种算法对于相似的子问题进行了重复的计算,因此不是一种高效的算法。实际上,该算法的运算时间是指数级增长的。 改进的方法是,我们可以通过保存已经算出的子问题的解来避免重复计算:

 1 int arr[n] = {0};
 2 
 3 int fib (int i)
 4 {
 5    if(i == 1)
 6    {
 7         arr[i] = 1;
 8    }
 9    else if(i = 2)
10    {
11         arr[i] = 1;
12    }
13    else 
14    {
15         arr[i] = arr[i - 1] + arr[i -2];
16    }
17   return arr[i];
18 }

将前n个已经算出的前n个数保存在数组map中,这样在后面的计算中可以直接易用前面的结果,从而避免了重复计算。算法的运算时间变为O(n);

动态规划几个经典问题

1.  最长单调子序列

2.  最长公共子序列

3.  背包问题

在后续的更新的文章中, 会陆续提到这几个问题, 等待更新……

 

 

 

posted @ 2013-09-12 22:12  Pazu  阅读(162)  评论(0编辑  收藏  举报