题目的意思就是给你两个串,然后你构造一个串,使这两个串都是它的子串.并且这个串要最短.
问最短多长,还有构造成最短长度的方法有几种.
首先我们可以知道,如果把两个串合并成一个串,肯定是可以满足条件的,但是不是最短的..
而且如果是两个串的公共子序列,那么就可以只算一遍.
所以最短应该是两个串长度的和,减掉两个串的最长公共子序列的长度.
接下来是有几种方法.
我们可以在算最长公共子序列的时候一起算.
如果str1[i] != str2[j]那么公共子序列d[i][j] = max { d[i - 1][j], d[i][j - 1]};
如果是d[i - 1][j]大,说明这个串就能多出f[i - 1][j]种,就是这时候最长的那串是str1[i - 1],str2[j]结束的.
反之则反...但是如果d[i - 1][j]和d[i][j - 1]相等,就两个都加上去.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 35;
ll f[N][N];
int d[N][N];
char str1[N];
char str2[N];
int n1,n2;
int main() {
int cas = 1;
int t;
scanf("%d",&t);
getchar();
while(t--) {
memset(f , 0 ,sizeof(f));
memset(d , 0 ,sizeof(d));
gets(str1 + 1);
gets(str2 + 1);
n1 = strlen(str1 + 1);
n2 = strlen(str2 + 1);
for (int i = 0 ; i < N ; i++) {
f[i][0] = f[0][i] = 1;
}
for (int i = 1 ; i <= n1 ; i++) {
for (int j = 1 ; j <= n2 ;j++) {
if(str1[i] == str2[j]) {
d[i][j] = d[i - 1][j - 1] + 1;
f[i][j] += f[i - 1][j - 1];
}
else {
d[i][j] = max(d[i - 1][j] , d[i][j - 1]);
if(d[i - 1][j] > d[i][j - 1])
f[i][j] += f[i - 1][j];
else if(d[i][j - 1] > d[i - 1][j])
f[i][j] += f[i][j - 1];
else
f[i][j] += (f[i - 1][j] + f[i][j - 1]);
}
}
}
printf("Case #%d: %d %lld\n",cas++ ,n1 + n2 - d[n1][n2] , f[n1][n2]);
}
}