这题最后就是求两个数,一个是由双亲序列得到的子序列的长度,还有一个是总共的方法数。第一个数按照LCS的DP方法求,最后的结果是两个串长度之和减去LCS的长度。第二个怎么求呢,困扰了好久,后来想明白了。num[i][j]表示从表示a串前i个元素和b串前j个元素所能得到的方法数。
若p1[i]=p2[j],那么c[i][j]=c[i-1][j-1],即p1串前i-1个元素和p2串前j-1个元素得到的组合串的末尾加上一个相同的元素,那么得到的新的组合串的个数还是和之前的组合串的个数不变。
若dp[i-1][j]>dp[i][j-1],那说明从dp[i-1][j]这种状态开始构建才能得到最终的LCS同时最终的组合串才不能漏掉共有的元素,所以num[i][i]=num[i-1][j],即在p1串i-1个元素和p2串j个元素组成的组合串的后面加上p1[i],那么得到的新的组合串的个数和之前的组合串的个数是相同的
若dp[i][j-1]>dp[i-1][j],道理和上面是一样的,所以num[i][j]=num[i][j-1],相当于在之前的组合串后面加上元素p2[j],得到新的组合串的个数不变
若dp[i][j-1]=dp[i-1][j],说明从两种状态都是能得到最终的LCS并且最终的组合串不会漏掉任何相同的公共元素,所以num[i][j]=num[i-1][j]+num[i][j-1] , 即用p1串的i-1个元素和p2串的j个元素组成的组合串的最后加上p1[i]得到新的组合串和之前的组合串个数相同,另外用p1串的i个元素和p2串的的j-1个元素组成的组合串的最后加上p2[j]得到新的组合串和之前的组合串个数相同,那么就是两者之和num[i][j]=num[i-1][j]+num[i][j-1]
输入用gets
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[50][50];
int num[50][50];
int main()
{
int t;
scanf("%d",&t);
getchar();
int c=1;
while(t--)
{
char p1[50],p2[50];
gets(p1);
gets(p2);
int l1=strlen(p1);
int l2=strlen(p2);
for ( int i = 0 ; i <= l1 ; ++ i )
for ( int j = 0 ; j <= l2 ; ++ j )
dp[i][j] = num[i][j] = 0;
for(int i=0;i<=l1;i++)
num[i][0]=1;
for(int j=0;j<=l2;j++)
num[0][j]=1;
for(int i=1;i<=l1;i++)
for(int j=1;j<=l2;j++)
{
if(p1[i-1]==p2[j-1])
dp[i][j]=dp[i-1][j-1]+1,num[i][j]=num[i-1][j-1];
else
{
if(dp[i-1][j]>dp[i][j-1])
dp[i][j]=dp[i-1][j],num[i][j]=num[i-1][j];
else if(dp[i-1][j]<dp[i][j-1])
dp[i][j]=dp[i][j-1],num[i][j]=num[i][j-1];
else
dp[i][j]=dp[i-1][j],num[i][j]=num[i-1][j]+num[i][j-1];
}
}
printf("Case #%d: %d %d\n",c++,l1+l2-dp[l1][l2],num[l1][l2]);
}
return 0;
}