​传送门​​​ 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:

abcicba
abdkscab

ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。

Input

第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000)

Output

输出最长的子序列,如果有多个,随意输出1个。

思路:

设 dp[i][j] 为a串前i个与b串前j个串里的最长公共子序列。
以O(mn)遍历a,b串,若a[i] == b[j],则dp[i][j]等于dp[i-1][j-1]+1,
否则dp[i][j] = max{dp[i-1][j], dp[i][j-1]}。
同时在遍历时用vis[][]指向当前的值是来自之前哪一个阶段。
最后从vis[m][n]开始,根据vis[i][j]中的“箭头”一步步回溯,当”箭头“指向左上角时,则说明此时的a[i] 或b[j]的值为公共子序列中的一部分,将其加入ans[cnt++]中,最后倒序输出ans就好了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
char vis[1010][1010];
int dp[1010][1010];
char ans[1010];
char a[1010],b[1010];
int main()
{
scanf("%s",a+1);
scanf("%s",b+1);
int lena = strlen(a+1),lenb = strlen(b+1);
for(int i = 1; i <= lena; i++)
{
for(int j = 1; j <= lenb; j++)
{
if(a[i] == b[j])
{
dp[i][j] = dp[i-1][j-1] + 1;
vis[i][j] = 'c';
}
else if(i > 0&& j > 0)
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
if(dp[i-1][j] > dp[i][j-1])
{
vis[i][j] = 'a';
}
else
{
vis[i][j] = 'b';
}
}
}
}
int cnt = 0;
int i = lena,j = lenb;
while(i>0||j>0)
{
if(vis[i][j] == 'a')
{
i--;
}
else if(vis[i][j] == 'b')
{
j--;
}
else
{
if(a[i] == b[j])
{
ans[cnt++] = a[i];
}
i--,j--;
}
}
for(int i = cnt-1; i >= 0; i--)
cout<<ans[i];
cout<<endl;
// cout<<dp[lena][lenb];
}