[dp]最长公共子序列问题

来源:互联网 发布:期现套利软件 编辑:程序博客网 时间:2024/06/06 21:41


最长公共子序列问题

给定两个字符串s1s2…sn和t1t2…tn。求出这两个字符串最长的公共子序列的长度.

限制条件:1<=n,m<=1000


输入:

n = 4

m = 4

s = "abcd"

t = "becd"


输出

3 ("bcd")


这个问题是被成为最长公共子序列(LCS)的著名问题。不妨用如下方式定义试试看:


定义:dp[i][j] = s[1]…s[i+1] 和 t[1]…t[j+1]对应的LCS的长度

由此,s[1]…s[i] 和 t[1]…t[j] 的公共子序列末尾追加上

(1)、s[i+1]

(2)、s[1] …s[i] 和 t[1] …t[j+1]的公共子序列

(3)、s[1] …s[i+1]和t[1]…t[j]的公共子序列

三者中的某一个,所以就有如下的递推关系成立:

 

(1) 当s[i+1] = t[j+1] 时,dp[i+1][j+1] = max(dp[i][j]+1,dp[i][j+1],dp[i+1][j])

(2) 当s[i+1] !=t[j+1] 时,dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j])


这个递推式可以用O(nm)的复杂度算出来,dp[n][m]就是LCS的长度。


j         i

    0    

  1(b)  

  2(e)  

  3(c)  

  4(d)  

0

0

0

0

0

0

1(a)

0

0

0

0

0

2(b)

0

1

1

1

1

3(d)

0

1

1

2

2

4(d)

0

1

1

2

3


#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int MAXN = 1005;int n,m;char s[MAXN],t[MAXN];int dp[MAXN][MAXN];int main(){    while(cin>>n>>m)    {        scanf("%s",s);        scanf("%s",t);        memset(dp,0,sizeof(dp));        for (int i = 0; i < n; i++)        {            for (int j = 0; j < m; j++)            {                if(s[i] == t[j])                    dp[i+1][j+1] = dp[i][j] + 1;                else                    dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]);            }        }        printf("%d\n",dp[n][m]);    }    return 0;}



0 0
原创粉丝点击