http://acm.hdu.edu.cn/showproblem.php?pid=1503
题意:给两个字符串,组成一个长度尽可能小的字符串,它包含上述两个字符串,且原字符串中的字符在该串中的相对位置不变。
思路:想到了最长公共子序列,但需要找到最长公共子序列是哪些。可以拿个二维数组记录第一个字符串i和第二个字符串j处的状态。然后根据状态递归,分别用一个数组记录公共字符在两个字符串中的位置。这样就找到了最长公共子序列中的字符。
然后按要求输出。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char s1[110],s2[110],s[210];
int pre[110][110];//pre[i][j]记录到达第一个字符串i与第二个字符串j的状态。
int len1,len2;
int dp[110][110];
int ind1[110],ind2[110];//记录公共字符在两字符串中的位置
int cnt;//记录公共子序列中字符的个数
//求最长公共子序列,并记录状态
void get_len()
{
memset(dp,0,sizeof(dp));
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(s1[i-1] == s2[j-1])
{
dp[i][j] = dp[i-1][j-1]+1;
pre[i][j] = 0;
}
else
{
if(dp[i-1][j] > dp[i][j-1])
{
pre[i][j] = 1;
dp[i][j] = dp[i-1][j];
}
else
{
pre[i][j] = 2;
dp[i][j] = dp[i][j-1];
}
}
}
}
}
//递归查找公共子序列中每个字符在两字符串中所对应下标
void dfs(int i, int j)
{
if(i == 0 || j == 0) return;
if(pre[i][j] == 1)
dfs(i-1,j);
else if(pre[i][j] == 2)
dfs(i,j-1);
else
{
dfs(i-1,j-1);
ind1[++cnt] = i-1;
ind2[cnt] = j-1;
}
}
int main()
{
while(~scanf("%s %s",s1,s2))
{
len1 = strlen(s1);
len2 = strlen(s2);
get_len();
cnt = 0;
dfs(len1,len2);
int count = 0;
int j = 0,k = 0;
for(int i = 1; i <= cnt; i++)
{//将公共字符之前的字符存在s中
for(; j <= ind1[i]-1; j++)
s[count++] = s1[j];
for(; k <= ind2[i]-1; k++)
s[count++] = s2[k];
s[count++] = s1[j];
j++;
k++;
}
while(s1[j] != '\0')
s[count++] = s1[j++];
while(s2[k] != '\0')
s[count++] = s2[k++];
s[count] = '\0';
printf("%s\n",s);
}
return 0;
}