题意:给出两串字符串,要你找出最小花费所能构造的基因序列,也就是要你找出最长公共子序列。以及所构造出来的新的基因序列有多少中不同的状态。
思路:求最长公共子序列(LIS),第一部分很好求出来,第二个不同的序列的个数会比较难点,不过想同了就相对简单了。
d[i][j]表示到i字符i以及到j字符所能找到的最长公共子序列。
当s1[i] == s2[j]时,d[i][j] = d[i - 1][j - 1] + 1;
当s1[i] != s2[j]时,d[i][j] = max(d[i - 1][j], d[i][j - 1] );
f[i][j]表示到i字符i以及到j字符所能构成的新的序列的个数。
当s1[i] == s2[j]时,f[i][j] = f[i - 1][j - 1] ;
当s1[i] != s2[j]时, d[i - 1][j] > d[i][j - 1] : f[i][j] = f[i - 1][j]、d[i - 1][j] < d[i][j - 1] : f[i][j] = f[i][j - 1]、d[i - 1][j] == d[i][j - 1] : f[i][j] = f[i - 1][j] + f[i][j - 1];
这里有个博客分析得挺好的
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 55;
char s1[MAXN], s2[MAXN];
int d[MAXN][MAXN];
long long f[MAXN][MAXN];
void dp(int l1, int l2) {
for (int i = 1; i <= l1; i++) {
for (int j = 1; j <= l2; j++) {
if (s1[i - 1] == s2[j - 1]) {
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 - 1][j] <d[i][j - 1])
f[i][j] = f[i][j - 1];
else
f[i][j]= f[i - 1][j] + f[i][j - 1];
}
}
}
}
int main() {
int cas, t = 1;
scanf("%d", &cas);
getchar();
while (cas--) {
gets(s1);
gets(s2);
// scanf("%s %s", s1, s2);
int l1 = strlen(s1);
int l2 = strlen(s2);
memset(d, 0, sizeof(d));
memset(f, 0, sizeof(d));
for (int i = 0; i < MAXN; i++) {
f[0][i] = f[i][0] = 1;
}
dp(l1, l2);
int ans = l1 + l2 - d[l1][l2];
printf("Case #%d: %d %lld\n", t++, ans, f[l1][l2]);
}
return 0;
}