题意:给定两个字符串,让你求一个最短的字符串,并且这个字符串包含给定的两个。
析:看到这个题,我知道是DP,但是,不会啊。。。完全没有思路么,我就是个DP渣渣,一直不会做DP。
最后还是参考了一下题解,主要是这样的,要想最短,就必须让两个字符串重复的最多,也就是LCS,
然后把剩下的不相同的字符再给补上,说起来容易,实现起来,难!反正对我来说是难。
然后根据LCS的原理,我们对这个两字符串,进行标记,什么意思呢,就是说,如果某个字符是公共字符,
等到输出时,我们只输出一次,而对于不是公共的,我们再分别输出,不过也要把握顺序,保证不会颠倒,
所以在这我们是用递归输出字符串,从最后递归到最前面,然后依次输出。
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100 + 10;
const int up = 2;
const int down = 3;
char s1[maxn], s2[maxn];
int mark[maxn][maxn], d[maxn][maxn];
void print(int i, int j){//递归输出
if(!i && !j) return ;
if(1 == mark[i][j]){
print(i-1, j-1);
printf("%c", s1[i]);
}
else if(up == mark[i][j]){//输出上面的
print(i-1, j);
printf("%c", s1[i]);
}
else if(down == mark[i][j]){//输出下面的
print(i, j-1);
printf("%c", s2[j]);
}
else if(!i && j){//第一串到起点了
print(i, j-1);
printf("%c", s2[j]);
}
else if(i && !j){//第二串到起点了
print(i-1, j);
printf("%c", s1[i]);
}
}
int main(){
// freopen("in.txt", "r", stdin);
while(~scanf("%s %s", s1+1, s2+1)){
int len1 = strlen(s1+1);
int len2 = strlen(s2+1);
memset(d, 0, sizeof(d));
memset(mark, 0, sizeof(mark));
for(int i = 1; i <= len1; ++i)
for(int j = 1; j <= len2; ++j)
if(s1[i] == s2[j]){ d[i][j] = d[i-1][j-1] + 1; mark[i][j] = 1; }
else if(d[i-1][j] >= d[i][j-1]){ d[i][j] = d[i-1][j]; mark[i][j] = up; }//表示要输出上面的一个
else{ d[i][j] = d[i][j-1]; mark[i][j] = down; }//表示要输出下面的一个
print(len1, len2);
printf("
");
}
return 0;
}