半夜ATM机前看书的那位

导航

动态规划和求解最长公共子序列介绍

动态规划是一种在数学计算机科学中使用的,用于求解包含重叠子问题最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。动态规划的思想是多种算法的基础,被广泛应用于计算机科学和工程领域。比较著名的应用实例有:求解最短路径问题,背包问题项目管理网络流优化等。

 

概述

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

 

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

步骤

 

  1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
  2. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

 

实例

 

斐波那契数列(Fibonacci polynomial)

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

   function fib(n)        if n = 0 or n = 1            return 1        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))

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

array map [0...n] = { 0 => 0, 1 => 1 } fib( n )     if ( map( n ) is cached )         return map( n )     return map( n ) = fib( n - 1 ) + fib( n - 2 ) 

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

 

 

 

最长公共子序列

 

问题描述

最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。
最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
例如,若x=<A,B,C,B,D,A,B>和y=<B,D,C,A,B,A>,则序列<B,C,A>是x和y的一个公共子序列,序列<B,C,B,A>也是x和y的一个公 共子序列。而且,后者是x和y的一个最长公共子序列,因为x和y没有长度大于4的公共子序列。
输入
输入数据有T组测试数据。测试数据的数目 (T)在输入的第一行给出。每组测试数据有两行:每行有一个字符串,每个字符串的长度都不超过20。
输出
每个用例,用一行输出其最大公共子序列的长度,如果没有公共子序列,则输出0。
样例输入
2
abceef
1235896
ABCBDAB
BDCABA
样例输出
0
4


代码:

  1 #include <iostream>

 2 using namespace std;
 3 void fun(int M[][100],char a[100],char b[100],int m,int n)
 4 {
 5  int i,j;
 6  for(i=1;i<=m;i++)M[i][0]=0;
 7  for(j=1;j<=n;j++)M[0][j]=0;
 8  for(i=1;i<=m;i++)
 9   for(j=1;j<=n;j++)
10   {
11    if(a[i-1]==b[j-1]){M[i][j]=M[i-1][j-1]+1;}
12    else if(M[i-1][j]>=M[i][j-1]){M[i][j]=M[i-1][j];}
13    else {M[i][j]=M[i][j-1];}
14   }
15 }
16 int main()
17 {
18  char a[100],b[100];
19  int c[100][100];
20  int m,n,k;
21  cin>>k;
22  while(k!=0)
23  {
24   cin>>a;
25   m=strlen(a);
26   cin>>b;
27   n=strlen(b);
28   fun(c,a,b,m,n);
29   cout<<c[m][n]<<endl;
30   k--;
31  }
32     return 0;
33 }

posted on 2011-08-17 21:10  zhizhesky  阅读(556)  评论(0编辑  收藏  举报