動態規划----最長公共子序列(C++實現)


最長公共子序列

  • 題目描述:給定兩個字符串s1 s2 … sn和t1 t2 … tm 。求出這兩個字符串的最長公共子序列的長度。字符串s1 s2 … sn的子序列指可以表示為s_{i1}s_{i2}s_{i k} { i1 < i2 < … < ik }的序列。
  • 輸入樣例

       2
       asdf
       adfsd
       123abc
       abc123abc

  • 輸出樣例

        3

        6

  • 解題思路:

這道題是被稱為最長公共子序列的問題(LCS,Longest Common Subsequence)的著名問題。這道題我們是用動態規划的思想來做的。我們先拿第一組測試用例,asdf 與 adfsd 作為例子來看一下這道題的思路。上圖!!

j / i 0 1(a) 2(s) 3(d) 4(f)
0 0 0 0 0 0
1(a) 0 1 1 1 1
2(d) 0 1 1 2 2
3(f) 0 1 1 2 3
4(s) 0 1 2 2 3
5(d) 0 1 2 2 3

做這種題,我們要用一個二維數組(dp[MAX_N][MAX_N])來存放每一個狀態的值。如圖所示,橫向代表i、縱向代表j,那么,每一個網格的值是怎么來的呢。在這里我們把每一個狀態即dp[i][j] 看做 s1 … si 和 t1 … tj 的LCS的長度。由此我們,s1 … s(i+1) 和 t1 … t(j+1) 對應的公共子列長度可能是:

當s(i+1) == t(j+1),在 s1 … si 和 t1 … tj 的公共子列末尾追加上s(i+1) 。

否則則可能是 s1 … si 和 t1 … t(j+1) 的公共子列或者 s1 … s(i+1) 和 t1 … tj 的公共子列最大值。

對應以下一個公式:

有了上面的公式我們就可以寫代碼了:

//最長公共子序列 #include<iostream> #include<string> #include<cstring> #include<stdlib.h> #define MAX 1001 using namespace std; int dp[MAX][MAX]; int main() { int N; cin >> N; while(N--) { string a,b; cin >> a >> b; memset(dp,0,sizeof(dp)); int len_a=a.size(),len_b=b.size(); for(int i=0;i<len_a;i++) { for(int j=0;j<len_b;j++) { if(a.at(i)==b.at(j)) dp[i+1][j+1]=dp[i][j]+1; else dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1]); } } cout << dp[len_a][len_b] << endl; a.clear(); b.clear(); } return 0; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM