关闭

动态规划问题详解(一)

标签: 动态规划
664人阅读 评论(0) 收藏 举报
分类:
  动态规划(英语:Dynamic programming,DP)[1]是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

  基本思想

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。  


  如何思考

  动态规划问题,其实就是一种求解最优解的一种思想。我这里说是一种思想,是因为它只提供了一种思考的方式,没有具体的公式,因此,动态规划是最难的算法之一。
  那么,我们应该从哪些方面来学习入手呢,在本文中,我打算采用大量的实例的方式来讲解。我们通过例一引用动态规划中有相关的概论。
  例一:硬币问题
  有面值分别是1元,3元,5元的三个硬币,请问,如何用最少的硬币凑足11元?
  我们随便一想,有好几种方案,如,11个1元的。3个3元的,2个一元的,两个5元的,一个1元的。如果要满足使用最少硬币的话,那么,只能是两个5元和一个1元的方案了。从计算机的角度讲,如何思考这个问题呢?
  我们现在要凑足11元,那么,我们只要凑足10(或者8元,或者6元)元要的硬币最小,则凑足11元,要的硬币是凑足10(或者8元,或者6元)元要的硬币+1。文字不好描述,我们定义一个数组
d[i]=min(d[i-v[j]]) + 1
d[i]中的i表示要凑足的数目。d[i]表示最小的硬币的数量。那么,我们把d[0]---d[11]全部都求出来。我们就知道d[11]的值是多少了。
d[0]是多少呢? 要凑足0元,最少需要多少个硬币? 我们自然想到d[0]=0. d[1]表示,要凑足1元,最小需要多少个硬币? 在1,3,5三种不同面值的硬币中,只有1元的可用,于是d[1]=d[1-1] +1,由于d[0]是最优的解,可以说d[1]=d[0] + 1也是最优的。 d[2]=d[2-1] +1. 我们再来看d[3],这个非常的关键.要凑足3元,最小需要多少个硬币。在1,,3,5,我们有两种硬币可选1和3. 如果选择1元的硬币,则d[3]=d[3-1] + 1. 如果选择3元的硬币 ,则 d[3]=d[3-3] +1 ,有两种方案,我们要保证d[3]用的硬币最小,则d[3]=d[3-3]+1是最优的解。依次类推,就可以求出d[11]的解了。

   通过上述的分析,我们总结一下,动态规划问题有哪些特点呢?

  规律原理

    1.最优化原则

    一个动态规划问题,可以分解成多个子问题求解,所有的子问题都是最优,则整个动态规划问题就是最优的解。各个子问题之间,是有依赖关系的。如:要凑足11元使用的硬币最少,则凑足10元使用的硬币也应该最少。11是依赖10的。它不像分治法一样,子问题之间是没有关系的。动态规划通过子问题最优,然后得到整体最优。

   2.无后效性

   它是这样一种性质:某阶段的状态一旦确定,则此后过程的演变不再受此前各种状态及决策的影响,简单的说,就是“未来与过去无关”,当前的状态是此前历史的一个完整总结,此前的历史只能通过当前的状态去影响过程未来的演变。具体地说,如果一个问题被划分各个阶段之后,阶段I中的状态只能由阶段I-1中的状态通过状态转移方程得来,与其它状态没有关系,特别是与未发生的状态没有关系。从图论的角度去考虑,如果把这个问题中的状态定义成图中的顶点,两个状态之间的转移定义为边,转移过程中的权值增量定义为边的权值,则构成一个有向无环加权图,因此,这个图可以进行“拓扑排序”,至少可以按它们拓扑排序的顺序去划分阶段。

无后向性,也称为马尔可夫性

  3.子问题的重叠性

   动态规划将原来具有指数级时间复杂度的搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决冗余,这是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其它的算法。
  第一个特性,我们很容易理解,对于第二个特性,我是这样理解的。我们仍然拿上述的例子来说明。我们要求d[11],如果我们用1元的硬币,则d[11]只依赖于d[10],而不是d[9],d[8].
  如果我们用3元的硬币,则d[11]只依赖于d[8],而不是d[7].如果我们选择用5元的硬币的话,那么则依赖于d[6],而不是d[5]。也就是说,未来只与当前的状态有关。
   对于第三个特性,我们也很容易理解,因为子问题都是最优的,它的值已经固定下来了,以后也没有必要再重新计算。
  现把上面例子的代码给出:
 
#include<stdio.h>
#include<stdlib.h>

/**
 * d[i]=min(i - v[j]) + 1
 * d[i] = total num ,eg, 11
 * 
 */

void main()
{
  printf("%d\n", get_coins_num(100));
}


int get_coins_num(int n)
{
  int num=0;
  int v[3]={1,3,5};
  int i,j;
  int* d = (int*)malloc((n+1) * sizeof (int));
  d[0]=0;
  for (i=1;i<=n;i++)
  {
    d[i] = 1024;
  }
  for (i=1;i<=n;i++)
  {
    for (j=0;j<3;j++)
    {
      if (i >= v[j]) 
      {
        int tmp = d[i];
        d[i] = d[i - v[j]] + 1;
        if ( d[i] > tmp) 
        {
          d[i]=tmp;  // if d[i] have more value, d[i]=min(d[i])
        }
      }
    }
  }
  num=d[n];
  free(d);
  return num;
}


 
 
 
 
 
 

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:123059次
    • 积分:2816
    • 等级:
    • 排名:第13454名
    • 原创:161篇
    • 转载:3篇
    • 译文:0篇
    • 评论:42条
    文章分类
    最新评论