DP算法

    DP算法又称动态规划,是信息学竞赛中选手必须熟练掌握的一种算法,

他以其多元性广受出题者的喜爱.动态规划首次进入信息学奥赛是在IOI94

(数字三角形),在国内首次出现是在NOI95。此后动态规划成为信息学奥

的必考算法之一。

动态规划一般可分为线性动规,区域动规,树形动规,背包动规四类。
举例
线性动规:拦截导弹,合唱队形,挖地雷,建学校,剑客决斗等
区域动规:石子合并, 加分二叉树,统计单词个数,炮兵布阵等
树形动规:贪吃的九头龙,二分查找树,聚会的欢乐,数字三角形等
背包问题:01背包问题,完全背包问题,分组背包问题,二维背包,装箱问题,
挤牛奶(同济ACM第1132题)等
应用实例
最短路径问题 ,项目管理,网络流优化等
问题求解模式
     动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策
的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活
动路线(通常是求最优的活动路线)。如图所示。动态规划的设计都有着一定的模式,一般要
经历以下几个步骤:  初始状态→│决策1│→│决策2│→…→│决策n│→结束状态
          (1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划
分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解
          (2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示
出来。当然,状态的选择要满足无后效性。  
         (3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据
上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但
事实上常常是反过来做,根据相邻两段各状态之间的关系来确定决策。
         (4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
    算法实现 
     动态规划的主要难点在于理论上的设计,也就是上面4个步骤的确定,一旦设计完成,实现部分就
会非常简单。使用动态规划求解问题,最重要的就是确定动态规划三要素:问题的阶段,每个阶段
的状态以及从前一个阶段转化到后一个阶段之间的递推关系。递推关系必须是从次小的问题开始到
较大的问题之间的转化,从这个角度来说,动态规划往往可以用递归程序来实现,不过因为递推可
以充分利用前面保存的子问题的解来减少重复计算,所以对于大规模问题来说,有递归不可比拟的
优势,这也是动态规划算法的核心之处。
             动态规划算法将问题的解决方案视为一系列决策的结果,与贪婪算法不同的是,在贪婪算法中,
每采用一次贪婪准则,便做出一个不可撤回的决策;而在动态规划算法中,还要考察每个最优决策
序列中是否包含一个最优决策子序列,即问题是否具有最优子结构性质。  动态规划算法的有效性依
赖于待求解问题本身具有的两个重要性质:最优子结构性质和子问题重叠性质。
             (1)最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题
具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
            (2)子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产
生的子问题并不总是新问题,有些子问题会被重复计算多次。
               动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算
结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,
从而获得较高的解题效率。  当我们已经确定待解决的问题需要用动态规划算法求解时,通常可以按照以
下步骤设计动态规划算法:
     (1)分析问题的最优解,找出最优解的性质,并刻画其结构特征;
     (2)递归地定义最优值;
     (3)采用自底向上的方式计算问题的最优值; 
     (4)根据计算最优值时得到的信息,构造最优解。
      1~3步是动态规划算法解决问题的基本步骤,在只需要计算最优值的问题中,完成这三个基本步骤就
可以了。如果问题需要构造最优解,还要执行第4步;此时,在第3步通常需要记录更多的信息,以
便在步骤4中,有足够的信息快速地构造出最优解。
例如:1
B - 最少拦截系统
Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u
Submit Status

Description

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统. 
 

Input

输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
 

Output

对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统. 
 

Sample Input

 
      
8 389 207 155 300 299 170 158 65
 

Sample Output

 
      
2 解答1:
[cpp] view plain copy
  1. #include  
  2. int main()  
  3. {  
  4.     int a[10001],b[10001]={0};  
  5.     int n,i,k,j;  
  6.     while(scanf("%d",&n)!=EOF)  
  7.     {k=0;  
  8.             b[0]=0;  
  9.         for(i=0;i
  10.         scanf("%d",&a[i]);  
  11.         for(i=0;i
  12.         {  
  13.                 for(j=0;j<=k;j++)  //总体思路是一个个接入,一个个与前面递减序列最小值相比较,  
  14.                 //如果比之小,替换再接入,如果比所有的都大,则再加入一个 递减序列   
  15.                 {  
  16.                 if(a[i]
  17.                 {  
  18.                 b[j]=a[i];  
  19.                 break;  
  20.                 }  
  21.                 else if(j==k)  
  22.                 {  
  23.                 b[++k]=a[i];  
  24.                 break;  
  25.                 }  
  26.                   
  27.                 }  
  28.         }  
  29.         printf("%d\n",k+1);  
  30.     }  
  31.     return 0;  
    例 2

描述

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = another sequence Z = is a subsequence of X if there exists a strictly increasing sequence of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = is a subsequence of X = with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y. 
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line. 
 

样例输入

 
      
abcfbc abfcab programming contest abcd mnp
 

样例输出

 
      
4 2 0
 
答案:
[cpp]  view plain copy
  1. #include  
  2. #include  
  3. #include  
  4. using namespace std;  
  5.  int d[1001][1001];  
  6. int main()  
  7. {  
  8.     int i,j;  
  9.     char a[1001];  
  10.     char b[1001];  
  11.         while(scanf("%s %s",a,b)!=EOF)  
  12.         {  
  13.              memset(d,0,sizeof(d));//保证了其他数据全为零  
  14.              int l1=strlen(a);  
  15.              int l2 = strlen(b);//必须将此处赋值,不然每次调用都会浪费很多时间  
  16.             for(i=0;i
  17.             for(j=0;j
  18.        {  
  19.            if(a[i]==b[j])  
  20.            {  
  21.                d[i+1][j+1]=d[i][j]+1;  
  22.            }  
  23.            else  
  24.            d[i+1][j+1]=max(d[i][j+1],d[i+1][j]);  
  25.        }  
  26.        printf ("%d\n",d[l1][l2]);  
  27.        }  
  28.        return 0;  
  29. }  
 



DP算法的思路就是由前面最优的情况来推算最优情况。对于这种题目还存在很多模板,
下面给大家一个模板链接点击打开链接不过还有很多自己 思考的东西,希望大家在以
后的做题中,慢慢探索,慢慢总结。


你可能感兴趣的:(DP)