题意:给定两个字符串,求一个最短的字符串使其中序列包含这两个字符串。
输出最短的长度和总的方案数。
题解:
由最长公共子序列方程转化而来:
最短长度
如果s[i]==t[j],len[i][j] = len[i-1][j-1] + 1,
否则len[i][j] = min(len[i][j-1], len[i-1][j]) + 1。
总方案数
如果s[i] == t[j], dp[i][j] = dp[i-1][j-1],
如果s[i] != t[j] 且len[i-1][j] != len[i][j-1], dp[i][j] = min(dp[i-1][j], dp[i][j-1]),
如果s[i] != t[j] 且len[i-1][j] == len[i][j-1],
dp[i][j] = dp[i-1][j] + dp[i][j-1]。
# include <stdio.h> # include <string.h> # define MAXN 40 int min(int a, int b){return a<b?a:b;} int main() { char s[MAXN], t[MAXN]; int T, i, j, slen, tlen, len[MAXN][MAXN], dp[MAXN][MAXN]; scanf("%d",&T); for(int k=1; k<=T; ++k) { memset(len, 0, sizeof(len)); memset(dp, 0, sizeof(len)); for(i=1; i<MAXN; ++i) len[0][i] = len[i][0] = i, dp[0][i] = dp[i][0] = 1; dp[0][0] = 1; scanf("%s%s",s+1,t+1); slen = strlen(s+1); tlen = strlen(t+1); for(i=1; i<=slen; ++i) for(j=1; j<=tlen; ++j) { if(s[i]==t[j]) { len[i][j] = len[i-1][j-1] + 1; dp[i][j] = dp[i-1][j-1]; } else { len[i][j] = min(len[i][j-1], len[i-1][j]) + 1; if(len[i-1][j] < len[i][j-1]) dp[i][j] = dp[i-1][j]; else if(len[i-1][j] > len[i][j-1]) dp[i][j] = dp[i][j-1]; else dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } printf("Case #%d: %d %d\n",k, len[slen][tlen], dp[slen][tlen]); } return 0; }