最长公共子序列(解析)

c[i,j]表示:(x1,x2....xi) 和 (y1,y2...yj) 的最长公共子序列的长度。(是长度哦,就是一个整数嘛)。公式的具体解释可参考《算法导论》动态规划章节

这张DP表很是重要,从中我们可以窥见最长公共子序列的来源,同时可以根据这张表打印出最长公共子序列的构成路径

 

 

最长公共子序列模板:

复制代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 1000;
 6 char a[N],b[N];
 7 int dp[N][N];
 8 int main()
 9 {
10     int lena,lenb,i,j;
11     while(scanf("%s%s",a,b)!=EOF)
12     {
13         memset(dp,0,sizeof(dp));
14         lena=strlen(a);
15         lenb=strlen(b);
16         for(i=1;i<=lena;i++)
17         {
18             for(j=1;j<=lenb;j++)
19             {
20                 if(a[i-1]==b[j-1])
21                 {
22                     dp[i][j]=dp[i-1][j-1]+1;
23                 }
24                 else
25                 {
26                     dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
27                 }
28             }
29         }
30         printf("%d\n",dp[lena][lenb]);
31     }
32     return 0;
33 }

复制代码

 

最长公共子序列打印路径的模板

递归法:

复制代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 1010;
 6 char a[N],b[N];
 7 int dp[N][N];
 8 int flag[N][N];
 9 void Print(int i,int j)
10 {
11     if(i==0||j==0)///递归终止条件
12     {
13         return ;
14     }
15     if(!flag[i][j])
16     {
17         Print(i-1,j-1);
18         printf("%c",a[i-1]);
19     }
20     else if(flag[i][j]==1)
21     {
22         Print(i-1,j);
23     }
24     else if(flag[i][j]=-1)
25     {
26         Print(i,j-1);
27     }
28 }
29 int main()
30 {
31     int lena,lenb,i,j;
32     while(scanf("%s%s",a,b)!=EOF)
33     {
34         memset(dp,0,sizeof(dp));
35         memset(flag,0,sizeof(flag));
36         lena=strlen(a);
37         lenb=strlen(b);
38         for(i=1;i<=lena;i++)
39         {
40             for(j=1;j<=lenb;j++)
41             {
42                 if(a[i-1]==b[j-1])
43                 {
44                     dp[i][j]=dp[i-1][j-1]+1;
45                     flag[i][j]=0;///来自于左上方
46                 }
47                 else
48                 {
49                     if(dp[i-1][j]>dp[i][j-1])
50                     {
51                         dp[i][j]=dp[i-1][j];
52                         flag[i][j]=1;///来自于左方
53                     }
54                     else
55                     {
56                         dp[i][j]=dp[i][j-1];
57                         flag[i][j]=-1;///来自于上方
58                     }
59                 }
60             }
61         }
62         Print(lena,lenb);
63     }
64     return 0;
65 }

复制代码

 

 

非递归,在这里因为是逆序的回溯,所以我使用了栈来存储路径

复制代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stack>
 4 #include<algorithm>
 5 using namespace std;
 6 #define N 1010
 7 int dp[N][N];
 8 char c;
 9 int main()
10 {
11     char a[N];
12     char b[N];
13     scanf("%s%s",a,b);
14     int la=strlen(a);
15     int lb=strlen(b);
16     memset(dp,0,sizeof(dp));
17     for(int i=1; i<=la; i++)
18     {
19         for(int j=1; j<=lb; j++)
20         {
21             if(a[i-1]==b[j-1])
22                 dp[i][j]=dp[i-1][j-1]+1;
23             else
24                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
25         }
26     }
27     int i=la,j=lb;
28     stack<char>s;
29     while(dp[i][j])
30     {
31         if(dp[i][j]==dp[i-1][j])///来自于左方向
32         {
33             i--;
34         }
35         else if(dp[i][j]==dp[i][j-1])///来自于上方向
36         {
37             j--;
38         }
39         else if(dp[i][j]>dp[i-1][j-1])///来自于左上方向
40         {
41             i--;
42             j--;
43             s.push(a[i]);
44         }
45     }
46     while(!s.empty())
47     {
48         c=s.top();
49         printf("%c",c);
50         s.pop();
51     }
52     return 0;
53 }

复制代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值