题目链接:http://lightoj.com/volume_showproblem.php?problem=1013
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std; const int maxn = ;
const int INF = 0x3f3f3f; int main()
{
//freopen("E:\\acm\\input.txt","r",stdin);
int T;
cin>>T;
for(int t=;t<=T;t++){
long long dp1[maxn][maxn],dp2[maxn][maxn]; /** dp1[i][j] = (i+j) - num(s1中前i个和s2中前j个的最长公共子序列)。
dp2[i][j]是包含s1中前i个和s2中前j个字母的最短字符串的个数。
**/
char s1[maxn],s2[maxn];
scanf("%s %s",s1+,s2+);
int Len1 = strlen(s1+), Len2 = strlen(s2+); for(int i=;i<=Len1;i++) dp1[i][] = i, dp2[i][] = ;
for(int i=;i<=Len2;i++) dp1[][i] = i, dp2[][i] = ; for(int i=;i<=Len1;i++)
for(int j=;j<=Len2;j++){
if(s1[i] == s2[j]){
dp1[i][j] = dp1[i-][j-] + ;
dp2[i][j] = dp2[i-][j-]; //这个时候直接把s1[i](s2[j])放在合成串s后面,所以加一;
}
else{
if(dp1[i-][j] == dp1[i][j-]){
dp1[i][j] = dp1[i-][j] + ;
dp2[i][j] = dp2[i-][j] + dp2[i][j-]; /**这个地方最难理解,dp1[i-1][j] == dp1[i][j-1] 得出s1[i-1] != s2[j] ,s1[i] != s2[j-1].
dp2[i-1][j] 可以理解为把s1[i]放在合成串s的最后的方法数,dp2[i][j-1]可以理解为把s2[j]放在合成串s最后的方法数。
加起来就的到总共的组合数
**/
}
else if(dp1[i-][j] > dp1[i][j-]){ //1.说明s1[i]能与s2[j-1]或者j-1之前某个组合在一起,而s2[j]不能。
dp1[i][j] = dp1[i][j-] + ; //取小的; 并添加了一个字母s2[j];
dp2[i][j] = dp2[i][j-]; //由1.这句知道:s2[j]只能添加在合成串s的最后。
}
else{ //此处分析同上。
dp1[i][j] = dp1[i-][j] + ; //取小的; 并添加了一个字母s1[i];
dp2[i][j] = dp2[i-][j];
}
}
}
printf("Case %d: %lld %lld\n",t,dp1[Len1][Len2],dp2[Len1][Len2]);
}
}
//总结下,这个dp1其实就是简单的LCS的变形,而dp2就是关键,这是参考别人的方法,只是觉得很精妙就学习下。