codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)
Posted 寄蜉蝣于天地,渺沧海之一粟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)相关的知识,希望对你有一定的参考价值。
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列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的一个子序列。
对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。
第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。
第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。
第1行输出上述两个最长公共子序列的长度。
第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。
ABCBDAB.
BACBBD.
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 }
以上是关于codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)的主要内容,如果未能解决你的问题,请参考以下文章