LightOJ1013 Love Calculator(DP)
容易猜测到包含s1、s2序列的串的最短长度是LCS(s1,s2) + ( len(s1) - LCS(s1,s2) ) + ( len(s2) - LCS(s1,s2) ) ,即:
len(s1)+len(s2)-LCS(s1,s2)
接下来求方案数,可以想到:
dp[k][i][j]表示由s1前i位和s2前j位的序列构成的长度为k的串的方案数
dp[k][i][j]是由dp[k-1][i-1][j]、dp[k-1][i][j-1]和dp[k-1][i-1][j-1]转移的,而从dp[k-1][i-1][j-1]转移则要满足s1[i]==s2[j]的条件。
转移方程我纠结了好久,才“试”出来:
dp[k][i][j] = (s1[i]==s2[j]) ? dp[k-1][i-1][j-1] : dp[k-1][i-1][j]+dp[k-1][i][j-1]
然后因为自己想的一个数据s1="aa",s2="ab"又纠结了好久,才“试”出初始状态是:
d[1][1][0]=d[1][0][1]=1
(s1[1]==s2[1]) ? d[1][1][1]=1 : d[1][1][1]=0
最后提交就AC了,有点不明觉厉。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int LCS[33][33]; 6 long long d[66][33][33]; 7 int main(){ 8 int t; 9 char s1[33],s2[33]; 10 scanf("%d",&t); 11 for(int cse=1; cse<=t; ++cse){ 12 scanf("%s%s",s1+1,s2+1); 13 14 int l1=strlen(s1+1),l2=strlen(s2+1); 15 memset(LCS,0,sizeof(LCS)); 16 for(int i=1; i<=l1; ++i){ 17 for(int j=1; j<=l2; ++j){ 18 if(s1[i]==s2[j]) LCS[i][j]=LCS[i-1][j-1]+1; 19 else LCS[i][j]=max(LCS[i-1][j],LCS[i][j-1]); 20 } 21 } 22 int len=l1+l2-LCS[l1][l2]; 23 24 memset(d,0,sizeof(d)); 25 d[1][1][0]=d[1][0][1]=1; 26 if(s1[1]==s2[1]) d[1][1][1]=1; 27 for(int k=2; k<=len; ++k){ 28 for(int i=0; i<=l1; ++i){ 29 for(int j=0; j<=l2; ++j){ 30 if(i==0 && j==0) continue; 31 if(i==0) d[k][i][j]=d[k-1][i][j-1]; 32 else if(j==0) d[k][i][j]=d[k-1][i-1][j]; 33 else if(s1[i]==s2[j]) d[k][i][j]=d[k-1][i-1][j-1]; 34 else d[k][i][j]=d[k-1][i-1][j]+d[k-1][i][j-1]; 35 } 36 } 37 } 38 39 printf("Case %d: %d %lld\n",cse,len,d[len][l1][l2]); 40 } 41 return 0; 42 }