1. 程式人生 > >動態規劃:求最長公共子序列和最長公共子串

動態規劃:求最長公共子序列和最長公共子串

最長公共子序列(LCS):

這同樣是一道經典題目,定義就不說了。

為了方便說明,我們用Xi代表{x1,x2,‥xi},用Yj代表{y1,y2,‥yj}。那麼,求長度分別為m,n的兩個序列X,Y的LCS就相當於求Xm與Yn的LCS。我們將其分割為區域性問題進行分析。

首先,求Xm與Yn的LCS要考慮一下兩種情況。

Ⅰ.

 xm=yn時,在Xm-1與Yn-1的LCS後面加上xm(=yn)就是Xm與Yn的LCS。

舉個例子,X={a,b,c,c,d,a}, Y={a,b,c,b,a} 時xm=yn,所以在Xm-1與Yn-1LCS({a,b,c} )後面加上 xm(=a)就是Xm

與Yn的LCS。

Ⅱ.

xm≠yn時,Xm-1Yn的LCS和XmYn-1的LCS中更長的一方就是Xm與Yn的LCS。

舉個例子,X={a,b,c,c,d,a}, Y={a,b,c,b,a} 時xm=yn,所以在Xm-1Yn的LCS為{a,b,c} ,Xm-1與Yn的LCS為{a,b,c,b},因此Xm-1與Yn的LCS就是Xm與Yn的LCS。

定義:

c[i][j]:為Xi與Yj的LCS的長度。

於是c[i][j]的值可由一下遞推關係求得:

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const
int maxn = 1000005; int dp[maxn][maxn]; int main() { string s1, s2; cin >> s1 >> s2; int a = s1.size(), b = s2.size(); for (int i = 0; i < a; i++) { for (int j = 0; j < b; j++) { if (s1[i] == s2[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]); } } cout << dp[a][b]; return 0; }

最長公共子串:

字串要求是連續的子序列,根據上面子序列的遞推公式,因此我們可以稍微改一下遞推公式,得到如下的遞推關係:

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int dp[maxn][maxn];
int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    int a = s1.size(), b = s2.size();
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < b; j++)
        {
            if (s1[i] == s2[j])
                dp[i + 1][j + 1] = dp[i][j] + 1;
            else
                dp[i + 1][j + 1] = 0;
        }
    }
    cout << dp[a][b];
    return 0;
}

如果有什麼不對的地方,歡迎大家指出哦(雖然知道沒什麼人看,但還是要說一下)。