动态规划基础

1.什么是动态规划:

动态规划,和分治法一样,是通过组合子问题的解而解决整个问题的。但不同的是,分治算法是指将问题划分成一些独立的子问题,递归求解各子问题,然后合并子问题的解而得到原问题的解。而动态规划适用于子问题不是独立的情况,也就是各子问题包含公共的子子问题。动态规划对每个子子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案。

 

2.动态规划中的几个重要性质:

2.1最优子结构:

用动态规划求最优化问题的第一步是描述最优解的结构。如果问题的一个最优解中包含子问题的最优解,则该问题具有最优子结构。当一个问题具有最优子结构时,提示我们动态规划可能会适用(注意,在这种情况下,贪心策略可能也是适用的)在动态规划中,我们利用子问题的最优解来构造问题的一个最优解。不妨举例说明,对于0-1背包问题中,若f[i][j]表示考虑前i个物品,背包容量是j时的背包内物品的最大值,则f[i][j] = max { f[i-1][j] , f[i-1][j-V[i]] } ,那么若f[i-1][j] 或者f[i-1][j-V[i]]不是最优的,则f[i][j]也不会是最优解,这就是最优子结构。

 2.2重复子问题:

所谓的重叠子问题,既当一个递归算法不断调用同一个问题时,我们说该最优问题包含重叠子问题的情况,针对这种情况提出了两种方案,一是:记忆化搜索(即备忘录算法);二是:自底向上的递推。这也是dp思想的关键所在。具体可以参见数字三角形的例子(参见刘汝佳《算法竞赛入门经典》),重复计算d(3,2),d(4,2)和d(4,3)的情况。

 2.3状态:

状态是一个很重要的概念,如果算法基础过关,那么,成功的为一个题目设计出状态的时候,动态规划已经完成了一大半。其实对于一个实际问题,要是能识别出来是用dp方法解决,并且能定义状态,问题就豁然开朗了。下一步就是找粗状态转移方程了。

 2.4状态转移方程:

状态转移方程是动态规划算法的核心所在,是实现算法的关键。动态规划中本阶段的状态往往是上一阶段状态和上一阶段决策的结果。也就是从一个状态到另一个状态用到的公式。例如0-1背包中的f[i][j] = max { f[i-1][j] , f[i-1][j-V[i]] }。

 

3.动态规划什么时候用:

动态规划通常应用于最优化问题。这类问题可能有许多种可行解,每个解都有一个值,而我们希望找到一个具有最优(最大或最小)值的解。称这样的问题为该问题的“一个”最优解(而不是“确定的”最优解),因为可能存在多个取最优解的值。

动态规划使用的基本条件就是:

1)最优子结构性质

2)子问题重叠性质

在应用动态规划时,对于重复出现的子问题,只需在第一次遇到时加以求解,并把答案保存起来,以便以后再遇到时直接引用,不必重新求解,从而大大地提高解题的效率。相比之下,一般的搜索技术,对于某个子问题,不管是否已经求解过,只要遇上,就会再次对它求解,因而影响了解题的效率。

 

4.动态规划算法实现的两种方式:

数字三角形的问题描述:有一个由非负整数组成的三角形,第一行只有一个数,除了最下面一行之外每个数的左下方和右下方各有一个数

    1

   3  2

  4  10  1

 4    3      2     20

4.1记忆化搜索:

Int d(int I ,int j)

{

  Ifd[i][j] >=0 return d[i][j];

  return d[i][j] = a[i][j]+(I ==n ? 0 : d[i+1][j] >?d[i+1][j+1]);

}

所谓的记忆化搜索,是若算过d[i][j]则进行记录,下次用到d[i][j]时直接用就可以了。这也是此题用dp和递归求解的主要区别。

4.2递推计算:

int I,j;

for(j = 1 ; j <= n ; j++) d[n][j] = a[n][j];

for(i = n-1 ; i >=1 ; i--)

{

  for(j = 1 ; j <=I ; j++)   {

    d[i][j] = =a[i][j]+d[i+1][j]>?d[i+1][j+1];

  }

}

这里的递推其实和记忆化搜索是差不多的,只是递推算法是自底向上的,需要明确各个状态的计算顺序。而记忆化搜索要记录每个状态是否已经算过。

 

5.动态规划算法例题:

数字三角形问题:典型例题

0-1背包问题:多阶段决策问题

DAG上的动态规划:把问题建模到图上,运用动态规划

 

6.使用动态规划应注意的问题:

6.1初值问题:

6.2状态转移过程

posted @ 2016-03-06 12:56  starskyhu  阅读(266)  评论(0编辑  收藏  举报