最长公共子序列(动规)


动规的常用的两种形式:

1,递归型:

优点:直观,容易编写

缺点:可能会因为层数太深爆栈,调用函数带来额外的时间开销。无法使用滚动数组节省空间。总体来说,比递推型慢。

2,递推型:

效率高,有可能使用滚动数组节省空间。

(poj1458)

 

 现在就按着之前动规的思路来

 

 递推公式:

 这个递推公式还是简单的但是如果是不等的条件呢?

 这个的else就是这一题专有的条件了,这个地方就很难了。怎么证明这一点呢?只要证明左边这个不会比右边的两项都大,又不会比右边两项都小。

 

 这个要证明的话要使用反证法,首先很显然不会比两者其中一个小,因为字符都多出来了,肯定不可能会小,但是难的是为什么不会比两者都大呢?假设第一个比后面两个都大。MaxLen(s1,s2)比MaxLen(s1,s2j-1)多了一个s1[j-1]如果第一个比第二个大的话,说明s1[j-1]是要起作用的,不然是不会大的。同理s2[i-1]也是要起作用的。所以这两者肯定是位于最长公共子序列里面而且是最后一个字符。如果是这样的话就不满足s1[i-1] != s2[j-1].(说实话这个我自己思考完全搞不清楚)

 ×处的位置有两种途径来推,第一种是对角线(s1[i-1]和s2[j-1]相等)还有一种是上面或者左边的最大值。

#include 
#include 
#include 
using namesapce std;
char s1[1000];
char s2[1000];
int maxlen[1000][1000];
int main(){
    while(cin>>s1>>s2){
        int len1 = strlen(s1);
        int len2 = strlen(s2);
        int Tmp;
        int i,j;
        for(i = 0;i<=len1;i++){
            maxlen[i][0] = 0;
        }
        for(j = 0;j<=len2;j++){
            maxlen[0][j] = 0;
        }
        for(i = 1;i<=len1;i++){
            for(j = 1;j<=len2;j++){
                if(s1[i-1] == s2[j-1]){
                    maxlen[i][j] = maxlen[i-1][j-1]+1;
                }else{
                    maxlen[i][j] = max(maxlen[i-1][j],maxlen[i][j-1]);
                }
            }
        }
        cout<endl;
    }

相关