動態規劃:求最長公共子序列和最長公共子串
阿新 • • 發佈:2018-11-29
最長公共子序列(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-1的LCS({a,b,c} )後面加上 xm(=a)就是Xm 與Yn的LCS。
Ⅱ.
xm≠yn時,Xm-1與Yn的LCS和Xm與Yn-1的LCS中更長的一方就是Xm與Yn的LCS。
舉個例子,X={a,b,c,c,d,a}, Y={a,b,c,b,a} 時xm=yn,所以在Xm-1與Yn的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; constint 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; }
如果有什麼不對的地方,歡迎大家指出哦(雖然知道沒什麼人看,但還是要說一下)。