动态规划算法的思路
动态规划法即 dynamic programming method (DP),是系统分析中的种常用方法。 动态规划法是20世纪50年代由贝尔曼(R. Bellman) 等人提出的,用来解决多阶段决策过程问题的一种最优化方法。多阶段决策过程是指把研究问题分成若干个相互联系的阶段,由每个阶段都作出决策,从而使整个过程达到最优化。很多情况下,利用动态规划法处理问题比线性规划法更为有效,特别是对于那些离散型问题。
动态规划法就是分多阶段进行决策,其基本思路如下:根据时空的特点,将复杂的问题划分为相互联系的若干个阶段,在选定系统行进方向之后,逆向从终点向始点计算,逐次对每个阶段寻找某种决策,使整个过程达到最优,所以又称为逆序决策过程。
按以下两个步骤可以设计一个标准 的动态规划算法:
(1)划分阶段
按照问题的时间或空间特征,把问题分为若千个阶段。在此需要注意,这若千个阶段定要是有序的或者是可排序的(即无后向性),否则问题就无法用动态规划求解。(2)选择状态
将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
在现实项目中,会经常遇到不能简单地分解成几个子问题的复杂问题,而是分解出一系列的子问题。如果再采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,那么求解过程会比较耗时,并日会按问题规模的增大而呈幂数级增加。为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法。
求两字符序列的最长公共字符子序列
所谓字符序列的子序列,是指从给定字符序列中随意去掉若干个字符后所形成的字符序列,这里的若干可能一个也不去掉。例如,X=ABCBDAB, Y=BCDB是X的一个子序列。我们需要考虑的是,如何将最长公共子序列问题分解成子问题,设A="a0,a1,......am-1", B="b0, b1... bn-1"并Z=“z0,z1, .... zk-1”为它们的最长公共子序列。可以证明有以下性质:
(1)如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1....,zk-2"是“a0,a1....,am-2和"b0, b1, ..., bn-2”的一个最长公共子序列。
(2) 如果am-1!=bn-1,则zk-1!=am-1, 说明“z0,z1....,zk-1"是“a0,a1....,am-2和"b0, b1, ..., bn-1”的一个最长公共子序列。
(3)如果am-1!=bn-1, 则zk-1!=bn-1, 说明“z0,z1....,zk-1"是“a0,a1....,am-1和"b0, b1, ..., bn-2”的一个最长公共子序列。
在找A和B的公共子序列,如果由am-1=bn-1,则进一步解决一个子问题,找“a0,a1......,am-2”和"b0,b1,.......,bn-2"的一个最长公共子序列;如果am-1!=bn-1,则需要解决两个子问题,找出"a0,a1,....,am-2"和"b0,b1,......,bn-1"的一个最长公共子序列和找出"a0,a1,......,am-1"和"b0,b1,......,bn-2"的一个最长公共子序列,再取两者中较长者作为A和B的最长公共子序列。
算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,所以最多调用(m+n)次就会遇到i=0或j=0的情况,此时开始返回。返回时与递归调用时方向相反,部署相同,所以算法时间复杂度为O(m+n)
#include<stdio.h> #include<string.h> #define MAXLEN 100 void LCSLength(char *x,char *y,int m, int n,int c[][MAXLEN],int b[][MAXLEN]) { int i,j; for(i=0;i<=m;i++){ c[i][0]=0; } for(j=1;j<=n;j++){ c[0][j]=0; } for(i=1;i<=m;i++){ for(j=1;j<=n;j++){ if(x[i-1]==y[j-1]){ c[i][j]=c[i-1][j-1]+1; b[i][j]=0; } else if(c[i-1][j]>=c[i][j-1]){ c[i][j]=c[i-1][j]; b[i][j]=1; } else{ c[i][j]=c[i][j-1]; b[i][j]=-1; } } } } void PrintLCS(int b[][MAXLEN],char *x,int i,int j) { if(i==0||j==0){ return ; } if(b[i][j]==0){ PrintLCS(b,x,i-1,j-1); printf("%c ",x[i-1]); } else if(b[i][j]==1){ PrintLCS(b,x,i-1,j); } else{ PrintLCS(b,x,i,j-1); } } void main() { char x[MAXLEN]={"ABCBDAB"}; char y[MAXLEN]={"BDCABA"}; int b[MAXLEN][MAXLEN]; int c[MAXLEN][MAXLEN]; int m,n; m=strlen(x); n=strlen(y); LCSLength(x,y,m,n,c,b); PrintLCS(b,x,m,n); getchar(); }