題目描述 Description
字符序列的子序列是指從給定字符序列中隨意地(不一定連續)去掉若干個字符(可能一個也不去掉)后所形成的字符序列。令給定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一個嚴格遞增下標序列<i0,i1,…,ik-1>,使得對所有的j=0,1,…,k-1,有xij = yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一個子序列。
對給定的兩個字符序列,求出他們最長的公共子序列長度,以及最長公共子序列個數。
輸入描述 Input Description
第1行為第1個字符序列,都是大寫字母組成,以”.”結束。長度小於5000。
第2行為第2個字符序列,都是大寫字母組成,以”.”結束,長度小於5000。
輸出描述 Output Description
第1行輸出上述兩個最長公共子序列的長度。
第2行輸出所有可能出現的最長公共子序列個數,答案可能很大,只要將答案對100,000,000求余即可。
樣例輸入 Sample Input
ABCBDAB.
BACBBD.
樣例輸出 Sample Output
4
7
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 #define maxn 5010 7 #define MOD 100000000 8 char A[maxn],B[maxn],cur; 9 int f[2][maxn], g[2][maxn]; 10 11 int main() 12 { 13 scanf("%s%s", A + 1, B + 1); 14 int na = strlen(A + 1), nb = strlen(B + 1); 15 A[na--] = '\0'; B[nb--] = '\0'; 16 17 cur=0; 18 for(int i = 1; i <= nb; i++) g[0][i] = 1; 19 g[0][0] = g[1][0] = 1; 20 21 for(int i = 1; i <= na; i++) 22 { 23 cur ^= 1; 24 for(int j = 1; j <= nb; j++) 25 { 26 if(A[i] == B[j]) f[cur][j] =f[cur^1][j-1] + 1; 27 else f[cur][j] = max(f[cur^1][j], f[cur][j-1]); 28 29 g[cur][j] = 0; 30 if(f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j]; 31 if(f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1]; 32 if(f[cur][j] == f[cur^1][j] && f[cur][j] == f[cur][j-1] && f[cur^1][j-1] == f[cur][j]) 33 g[cur][j] -= g[cur^1][j-1]; 34 if(A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1]; 35 if(g[cur][j] > MOD) g[cur][j] %= MOD; 36 if(g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD; 37 } 38 } 39 printf("%d\n%d\n", f[cur][nb], g[cur][nb]); 40 return 0; 41 }
參考1:http://blog.csdn.net/moep0/article/details/52760974
參考2:http://blog.csdn.net/litble/article/details/67640655
算法分析:
第一個問題可以參考最長公共子序列原題的題解。
這里摘抄參考1里面的兩段代碼留存:
代碼一:使用了滾動數組。

1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <stack> 6 #include <vector> 7 #include <queue> 8 #include <cstring> 9 #include <string> 10 #include <map> 11 #include <set> 12 using namespace std; 13 14 const int BufferSize = 1 << 16; 15 char buffer[BufferSize], *Head, *Tail; 16 inline char Getchar() { 17 if(Head == Tail) { 18 int l = fread(buffer, 1, BufferSize, stdin); 19 Tail = (Head = buffer) + l; 20 } 21 return *Head++; 22 } 23 int read() { 24 int x = 0, f = 1; char c = Getchar(); 25 while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } 26 while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } 27 return x * f; 28 } 29 30 #define maxn 5010 31 #define MOD 100000000 32 char A[maxn], B[maxn], cur; 33 int f[2][maxn], g[2][maxn]; 34 35 int main() { 36 scanf("%s%s", A + 1, B + 1); 37 int na = strlen(A + 1), nb = strlen(B + 1); 38 A[na--] = '\0'; B[nb--] = '\0'; 39 40 for(int i = 1; i <= nb; i++) g[0][i] = 1; g[0][0] = g[1][0] = 1; 41 for(int i = 1; i <= na; i++) { 42 cur ^= 1; 43 for(int j = 1; j <= nb; j++) { 44 f[cur][j] = max(f[cur^1][j], f[cur][j-1]); 45 if(A[i] == B[j]) f[cur][j] = max(f[cur][j], f[cur^1][j-1] + 1); 46 g[cur][j] = 0; 47 if(f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j]; 48 if(f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1]; 49 if(f[cur][j] == f[cur^1][j] && f[cur][j] == f[cur][j-1] && f[cur^1][j-1] == f[cur][j]) g[cur][j] -= g[cur^1][j-1]; 50 if(A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1]; 51 if(g[cur][j] > MOD) g[cur][j] %= MOD; 52 if(g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD; 53 } 54 } 55 56 printf("%d\n%d\n", f[cur][nb], g[cur][nb]); 57 58 return 0; 59 }
代碼二:不使用滾動數組,假如測試數據較小,可以AC。

1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #define mod 100000000 7 using namespace std; 8 string a,b; 9 int f[5005][5005],g[5005][5005]; 10 int main(){ 11 cin>>a>>b; 12 int l1=a.length()-1,l2=b.length()-1; 13 a=' '+a,b=' '+b; 14 for(int i=0;i<=l1;i++)g[i][0]=1; 15 for(int i=0;i<=l2;i++)g[0][i]=1; 16 for(int i=1;i<=l1;i++) 17 for(int j=1;j<=l2;j++) 18 { 19 if(a[i]==b[j]) 20 { 21 f[i][j]=f[i-1][j-1]+1; 22 g[i][j]=g[i-1][j-1]; 23 if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod; 24 if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod; 25 } 26 else 27 { 28 f[i][j]=max(f[i-1][j],f[i][j-1]); 29 if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod; 30 if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod; 31 if(f[i][j]==f[i-1][j-1])g[i][j]-=g[i-1][j-1],g[i][j]=(g[i][j]+mod)%mod; 32 } 33 } 34 cout<<f[l1][l2]<<endl<<g[l1][l2]%mod; 35 return 0; 36 }