题意:给定两个字符串,求一个最短的字符串使其中序列包含这两个字符串。
输出最短的长度和总的方案数。
题解:
由最长公共子序列方程转化而来:
最短长度
如果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;
}