题目
样例
先求出最长公共子序列LCS,然后就是掉渣天的回溯法输出只含有一个公共序列并且包含输入的两个序列,LCS的变形题。这里需要设置一个标志数组,用来记录dp的刷新路径。从而在回溯的时候根据标志数组来沿着路径输出。
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define _for1(i,a,b) for( int i=(a); i<(b); ++i)
#define _for2(j,a,b) for( int j=(a); j<(b); ++j)
#define _rep1(i,a,b) for( int i=(a); i<=(b); ++i)
#define _rep2(j,a,b) for( int j=(a); j<=(b); ++j)
typedef long long ll;
using namespace std;
#define Max 102
int f[Max][Max];
int vis[Max][Max];
char s[Max], t[Max];
int len1, len2;
void LCS() //计算LCS,并用vis标记数组记录f数组的传递过程
{
int i, j;
mem(vis, 0);
mem(f, 0);
_rep1(i, 1, len1){
_rep2(j, 1, len2){
if (s[i - 1] == t[j - 1]){
f[i][j] = f[i - 1][j - 1] + 1;
// cout<<s[i-1]<<" ";
vis[i][j] = 1;
}
else if (f[i - 1][j] >= f[i][j - 1]){
f[i][j] = f[i - 1][j]; //从上面传递下来
vis[i][j] = 3;
}
else{
f[i][j] = f[i][j - 1]; //从左边传递下来
vis[i][j] = 2;
}
}
}
return;
}
void output(int i, int j) //回溯输出
{
if (i == 0 && j != 0){
output(i, j - 1);
printf("%c", t[j - 1]);
}
else if (i != 0 && j == 0){
output(i - 1, j);
printf("%c", s[i - 1]);
}
else if (i == 0 && j == 0)
return;
else if (vis[i][j] == 1){
output(i - 1, j - 1);
printf("%c", s[i - 1]);
}
else if (vis[i][j] == 3){
output(i - 1, j);
printf("%c", s[i - 1]);
}
else{
output(i, j - 1);
printf("%c", t[j - 1]);
}
return;
}
int main()
{
int i, j;
while (scanf("%s%s", s, t) != EOF)
{
len1 = strlen(s), len2 = strlen(t);
LCS();
output(len1, len2);
printf("\n");
}
}