题目链接:hdu-1503
题目大意:给你两个单词,将两个单词拼在一起,使新单词包括两个单词,并且是最短的
思路:把属于最长公共子序列的元素输出一遍,别的按原序输出便可,先打出最长公共子序列长度的dp表,开始回溯,最后一个字母相等的时候,说明是最长公共子序列的元素,向斜上方走, 当最后两个字符不相等的时候,说明不属于最长公共子序列元素,向左边或者上边中的最大值走,知道dp==0为直,再把没走过的字符加到前面,就是组成的最短的新单词;
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int m, n, i, j, k, l1,l2, t,l;
int dp[105][105];//dp为s1的前i个字符和s2的前j个字符的最长公共子序列
string s1, s2,s,a,b;
while (cin >> a >> b)
{
memset(dp, 0, sizeof(dp));// 第0行为了方便计算
s1+='0';//让s1下标从1开始,看着顺眼
s1+=a;
s2+='0';
s2+=b;
l1 = s1.size()-1;//输入的字符的长度
l2 = s2.size()-1;
for(i=1;i<=l2;i++)//lcs打表
for (j = 1; j <= l1; j++)
{
if (s2[i] == s1[j])dp[i][j] = dp[i - 1][j - 1] + 1;//最后一个字符相等则长度加1
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);//不等的话取去除最后一个字母的最大dp
}
//从最后字符开始回溯,非共有走左边和上边的最大值,共有走左边斜上方,记录走过的字符
m=l1;//从最后一个字符开始
n=l2;
while(1)
{
if(dp[n][m]==0)//如果前面没有个公共子序列的元素
{
//加上剩余的字符
for(i=n;i>=1;i--)
s+=s2[i];
for(j=m;j>=1;j--)
s+=s1[j];
break;
}
if(s1[m]==s2[n])//最后一个字符相等,则说明属于最长公共子序列,两个字符串分别去除最后一个字符,却直记录一次
{
s+=s1[m];
m--;
n--;
}
else
{
if(dp[n-1][m]>=dp[n][m-1])//根据题意,上边大于等于左边走上边
{
s+=s2[n];
n--;
}
else
{
s+=s1[m];
m--;
}
}
}
reverse(s.begin(), s.end());//将s反转
cout << s << endl;
s1.clear();//清空
s2.clear();
s.clear();
}
return 0;
}