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 }