题目:https://cn.vjudge.net/problem/HDU-1503
题意:输入两个长度不超过一百的非空字符串,求一个字符串,使该字符串存在子序列分别是输入的两字符串,要求所求字符串最短。有多个答案时,输出任意一个。
思路:要找最短的包含两字符串的字符串,把输入的两字符串,公共部分输出一次,其他部分按照一定顺序各自输出。具体做法:找出最长公共子序列,标记好LCS的每个字符在原字符串中对应的下标,然后以这些匹配的位置将字符串分段输出即可。
例如:
上图S1, S2两字符串,a b两字符分别对应匹配
那么答案即是
S1part1 + S2part1 + a + S1part2 + S2part2 + b + S1part3 + S2part3
或者
S2part1 + S1part1 + a + S2part2 + S1part2 + b + S2part3 + S1part3
代码:C++
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 100 + 10;
string s1, s2;
int n1, n2;
int d[maxn][maxn];
int p[maxn][maxn]; // -1, 0, 1, 2
void LCS()
{
memset(d, 0, sizeof(d));
memset(p, -1, sizeof(p));
for (int i = 0; i < n1; i++)
{
for (int j = 0; j < n2; j++)
{
if (s1[i] == s2[j])
{
if (i == 0 || j == 0)
{
d[i][j] = 1;
}
else
{
d[i][j] = d[i - 1][j - 1] + 1;
}
p[i][j] = 0;
}
if (i != 0 && d[i - 1][j] > d[i][j])
{
d[i][j] = d[i - 1][j];
p[i][j] = 1;
}
if (j != 0 && d[i][j - 1] > d[i][j])
{
d[i][j] = d[i][j - 1];
p[i][j] = 2;
}
}
}
}
void print()
{
string ans = "";
int i = n1 - 1, j = n2 - 1;
int prei = i, prej = j;
while (i >= 0 && j >= 0)
{
if (p[i][j] == 0)
{
for (int k = prej; k > j; k--)
{
ans.push_back(s2[k]);
}
for (int k = prei; k > i; k--)
{
ans.push_back(s1[k]);
}
ans.push_back(s1[i]);
i--;
j--;
prei = i;
prej = j;
}
else if (p[i][j] == 1)
{
i--;
}
else if(p[i][j] == 2)
{
j--;
}
else //if(p[i][j] == -1)
{
break;
}
}
for (int k = prej; k >= 0; k--)
{
ans.push_back(s2[k]);
}
for (int k = prei; k >= 0; k--)
{
ans.push_back(s1[k]);
}
reverse(ans.begin(), ans.end());
cout << ans << endl;
}
int main()
{
while (cin >> s1 >> s2)
{
n1 = s1.size();
n2 = s2.size();
LCS();
print();
}
return 0;
}