zoukankan      html  css  js  c++  java
  • codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)

    题目描述 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--] = ''; B[nb--] = '';
    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
    %d
    ", 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参考2的分析和代码自己理解。

    这里摘抄参考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--] = ''; B[nb--] = '';
    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
    %d
    ", f[cur][nb], g[cur][nb]);
    57      
    58     return 0;
    59 }
    View Code

    代码二:不使用滚动数组,假如测试数据较小,可以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 }
    View Code
  • 相关阅读:
    iBase4J部署总结
    就像我爱你,不仅仅是今天
    10年千亿美元,紫光集团目标跻身全球前五的存储器企业
    ddd
    微信的API都是通过https调用实现的,分为post方法调用和get方法调用。不需要上传数据的采用get方法(使用IntraWeb开发)
    管道通信实例(A程序作为服务器,不断从B程序接收数据,并发送到C程序中)
    HTTP协议中的短轮询、长轮询、长连接和短连接
    细说gulp
    Linux IO 调度器
    SPARK如何使用AKKA实现进程、节点通信
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/7435750.html
Copyright © 2011-2022 走看看