51 nod 1006 最长公共子序列Lcs

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1006

参考博客 :http://blog.csdn.net/yysdsyl/article/details/4226630

recursive formula 

引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。

计算 LCS 复杂度  O(n*m).由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故打印输出算法时间复杂度为Θ(m + n)。

打印序列,非递归。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 #include <queue>
 6 #include <algorithm>
 7 #define MAXN 1111
 8 #define MAXM 222222
 9 #define INF 1000000000
10 using namespace std;
11 
12 char s[MAXN],t[MAXN],res[MAXN];
13 int dp[MAXN][MAXN],flag[MAXN][MAXN];
14 
15 void LCS(int n,int m)
16 {
17     memset(dp,0,sizeof(dp));
18     memset(flag,0,sizeof(flag));
19     for(int i=1;i<=n;i++)
20         for(int j=1;j<=m;j++)
21         {
22             if(s[i-1]==t[j-1])
23             {
24                 dp[i][j]=dp[i-1][j-1]+1;
25                 flag[i][j]=1;
26             }
27             else if(dp[i][j-1]>dp[i-1][j])
28             {
29                 dp[i][j]=dp[i][j-1];
30                 flag[i][j]=2;
31             }
32             else
33             {
34                 dp[i][j]=dp[i-1][j];
35                 flag[i][j]=3;
36             }
37         }
38     //printf("%d
",dp[n][m]);
39 }
40 
41 void getLCS(int n,int m)
42 {
43     int k=0;
44     while(n>0&&m>0)
45     {
46         if(flag[n][m]==1)
47         {
48             res[k++]=s[n-1];
49             n--;
50             m--;
51         }
52         else if(flag[n][m]==2) m--;
53         else if(flag[n][m]==3) n--;
54     }
55     for(int i=k-1;i>=0;i--)
56     {
57         printf("%c",res[i]);
58     }
59     printf("
");
60 }
61 
62 int main()
63 {
64     //freopen("a.txt","r",stdin);
65     scanf("%s %s",s,t);
66     //printf("%s %s
",s,t);
67     int l1=strlen(s),l2=strlen(t);
68     LCS(l1,l2);
69     /*for(int i=0;i<=l1;i++)
70     {
71         for(int j=0;j<=l2;j++)
72             printf("%d ",flag[i][j]);
73         printf("
");
74     }
75     printf("
");*/
76     getLCS(l1,l2);
77     return 0;
78 }
View Code

递归

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=1111;
 4 int dp[maxn][maxn],flag[maxn][maxn];
 5 int n,m;
 6 char s[maxn],t[maxn];
 7 
 8 void LCS(int n,int m)
 9 {
10     memset(dp,0,sizeof(dp));
11     memset(flag,0,sizeof(flag));
12     for(int i=0;i<n;i++)
13         for(int j=0;j<m;j++)
14         {
15             if(s[i]==t[j])
16             {
17                 dp[i+1][j+1]=dp[i][j]+1;
18                 flag[i+1][j+1]=1;
19             }
20             else if(dp[i+1][j]>dp[i][j+1])
21             {
22                 dp[i+1][j+1]=dp[i+1][j];
23                 flag[i+1][j+1]=2;
24             }
25             else
26             {
27                 dp[i+1][j+1]=dp[i][j+1];
28                 flag[i+1][j+1]=3;
29             }
30         }
31    // printf("%d
",dp[n][m]);
32 }
33 
34 void printLCS(int n,int m)
35 {
36     if(n==0||m==0) return;
37 
38     if(flag[n][m]==1)
39     {
40         printLCS(n-1,m-1);
41         printf("%c",s[n-1]);
42     }
43     else if(flag[n][m]==2) printLCS(n,m-1);
44     else printLCS(n-1,m);
45 }
46 int main()
47 {
48     //freopen("a.txt","r",stdin);
49     scanf("%s %s",s,t);
50     int l1=strlen(s),l2=strlen(t);
51     LCS(l1,l2);
52     printLCS(l1,l2);
53     return 0;
54 }
View Code

下面这种是比较简洁的。去掉了标记数组。

 1 #include<string>
 2 #include<iostream>
 3 using namespace std;
 4 const int maxn = 1111;
 5 
 6 int dp[maxn][maxn]={0};
 7 string a,b;
 8 
 9 void LCS(int n,int m)
10 {
11     for(int i=1;i<=n;i++)
12         for(int j=1;j<=m;j++)
13         if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1;
14         else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
15 }
16 
17 int main()
18 {
19     cin>>a>>b;
20     int l1=a.size(),l2=b.size();
21     LCS(l1,l2);
22     int len=dp[l1][l2];
23     string ans;
24     int i=l1,j=l2;
25     while(dp[i][j])
26     {
27         if(dp[i][j]==dp[i-1][j]) i--;
28         else if(dp[i][j]==dp[i][j-1]) j--;
29         else ans.push_back(a[i-1]),i--,j--;
30     }
31     for(int i=len-1;i>=0;i--)
32         cout<<ans[i];
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/nowandforever/p/4429099.html