题意:给出两个字符串,求能满足子串(可以不连续)中包含给出的两个字符串的最短字符串.
思路:本质上就是LCS问题,做法是先找出两个串的LCS,并记录其位置
设dp[i][j]为A串以第i个字符结尾B串以第j个字符结尾的LCS, 用path数组来记录路径,
如果A[i] == B[j] 那么dp[i][j] = dp[i - 1][j - 1].
否则 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) .
用两个数组pos1, pos2分别代表LCS在各自串中的位置.
那么不是LCS的字符就要按照一定的顺序打印,详细的看代码吧
#include <cstdio>
#include <string>
#include <iostream>
#include <memory.h>
using namespace std;
const int MAX = 128;
int dp[MAX][MAX];
int pos1[MAX], pos2[MAX], cnt;
char path[MAX][MAX];
char f1[MAX], f2[MAX];
void traverse(int i, int j){
if(i == 0 || j == 0)return;
if(path[i][j] == 0){
traverse(i - 1, j - 1);
pos1[cnt] = i;
pos2[cnt++] = j;
}else if(path[i][j] == 1){
traverse(i - 1, j);
}else{
traverse(i, j - 1);
}
}
int main(int argc, char const *argv[]){
while(scanf("%s%s", f1 + 1, f2 + 1) == 2){
memset(dp, 0, sizeof(dp));
int len1 = strlen(f1 + 1), len2 = strlen(f2 + 1);
for(int i = 1; i <= len1; ++i){
for(int j = 1; j <= len2; ++j){
if(f1[i] == f2[j]){
dp[i][j] = dp[i - 1][j - 1] + 1;
path[i][j] = 0;
}else if(dp[i - 1][j] > dp[i][j - 1]){
dp[i][j] = dp[i - 1][j];
path[i][j] = 1;
}else{
dp[i][j] = dp[i][j - 1];
path[i][j] = 2;
}
}
}
cnt = 1;
traverse(len1, len2);
pos1[cnt] = len1 + 1;
pos2[cnt++] = len2 + 1;
for(int i = 1; i < cnt; ++i){
for(int j = pos1[i - 1] + 1; j < pos1[i]; ++j){
printf("%c", f1[j]);
}
for(int j = pos2[i - 1] + 1; j < pos2[i]; ++j){
printf("%c", f2[j]);
}
if(i != cnt - 1)
printf("%c", f1[pos1[i]]);
}
printf("\n");
}
return 0;
}