HDU1159 Common Subsequence

來源:互聯網
上載者:User
                                                   
Common Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 17390    Accepted Submission(s): 7290

Problem DescriptionA subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is a subsequence of X if there exists a strictly increasing
sequence <i1, i2, ..., ik> of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of
the maximum-length common subsequence of X and Y.
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard
output the length of the maximum-length common subsequence from the beginning of a separate line. 

Sample Input

abcfbc abfcabprogramming contest abcd mnp
 

Sample Output

420
 

SourceSoutheastern Europe 2003 

RecommendIgnatius

解題思路:本題是求兩個字串的最長公用子序列。
                 先用公用子串引入處理方法

最長公用子串(LCS)

找 兩個字串的最長公用子串,這個子串要求在原字串中是連續的。其實這又是一個序貫決策問題,可以用動態規劃來求解。我們採用一個二維矩陣來記錄中間的結 果。這個二維矩陣怎麼構造呢?直接舉個例子吧:"bab"和"caba"(當然我們現在一眼就可以看出來最長公用子串是"ba"或"ab")

   b    a    b

c      0     0    0

a      0   
1     0

b      1    
0     1

a      0     1 0

我們看矩陣的斜對角線最長的那個就能找出最長公用子串。

不過在二維矩陣上找最長的由1組成的斜對角線也是件麻煩費時的事,下面改進:當要在矩陣是填1時讓它等於其左上方元素加1。

   b     a     b

c       0     0     0

a      0     1    0

b      1 0      2

a      0    2    0

這樣矩陣中的最大元素就是 最長公用子串的長度。

在構造這個二維矩陣的過程中由於得出矩陣的某一行後其上一行就沒用了,所以實際上在程式中可以用一維數組來代替這個矩陣。

                同理處理最長公用子序列

最長公用子序列

最長公用子序列與最長公用子串的區別在於最長公用子序列不要求在原字串中是連續的,比如ADE和ABCDE的最長公用子序列是ADE。

我們用動態規劃的方法來思考這個問題如是求解。首先要找到狀態轉移方程:

等號約定,C1是S1的最右側字元,C2是S2的最右側字元,S1‘是從S1中去除C1的部分,S2'是從S2中去除C2的部分。

LCS(S1,S2)等於下列3項的最大者:

(1)LCS(S1,S2’)

(2)LCS(S1’,S2)

(3)LCS(S1’,S2’)--如果C1不等於C2; LCS(S1',S2')+C1--如果C1等於C2;

邊界終止條件:如果S1和S2都是空串,則結果也是空串。

下面我們同樣要構建一個矩陣來儲存動態規划過程中子問題的解。這個矩陣中的每個數字代表了該行和該列之前的LCS的長度。與上面剛剛分析出的狀態轉移議程相對應,矩陣中每個格子裡的數字應該這麼填,它等於以下3項的最大值:

(1)上面一個格子裡的數字

(2)左邊一個格子裡的數字

(3)左上方那個格子裡的數字(如果 C1不等於C2); 左上方那個格子裡的數字+1( 如果C1等於C2)

舉個例子:

        G  C T  A

   0    0 0  0   0

G  0  1 1 1  1

B  0  11
1 1

T  0  1 1 2  2

A      0  1 1  2  3

填寫最後一個數字時,它應該是下面三個的最大者:

(1)上邊的數字2

(2)左邊的數字2

(3)左上方的數字2+1=3,因為此時C1==C2

所以最終結果是3。

在填寫過程中我們還是記錄下目前的儲存格的數字來自於哪個儲存格,以方便最後我們回溯找出最長公用子串。有時候左上、左、上三者中有多個同時達到最大,那麼任取其中之一,但是在整個過程中你必須遵循固定的優先標準。在My Code中優先順序別是左上>左>上。

給出了回溯法找出LCS的過程:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int num[1002][1002];int main(){    int i,j,k;    char a[1002],b[1002];    while(scanf("%s",a)!=EOF)    {        scanf("%s",b);        int stra=strlen(a);        int strb=strlen(b);        memset(num,0,sizeof(num));        for(i=1;i<=stra;i++)        {            for(j=1;j<=strb;j++)            {                k=num[i-1][j-1];                if(a[i-1]==b[j-1])                    k++;                num[i][j]=max(max(num[i][j-1],num[i-1][j]),k);  //狀態方程            }        }        printf("%d\n",num[stra][strb]);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.