【DP】最长公共子序列

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

  第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。

  第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。

Output

  第1行输出上述两个最长公共子序列的长度。

  第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。

Sample Input

ABCBDAB.

BACBBD.

Sample Output

47

Solution  

  DP,记f[i][j]为a串前i个字符与b串前j个字符的最长公共子序列,记g[i][j]为a串前i个字符与b串前j个字符的最长公共子序列的个数。

  f[i][j]={ f[i+1][j+1],a[i]==b[j];

      max(f[i-1][j],f[j-1][i]),a[i]!=b[j];}

  注意细节的处理,可以用string将a串整体后移一位,a=‘ ‘+a;

Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;
 6
 7 typedef long long LL;
 8
 9 const int sm = 5000+10;
10 const int mod = 100000000;
11
12 string a,b;
13 int la,lb,ans,c;
14 int f[sm][sm],g[sm][sm];
15
16 //g[i][j]记录a中前i位与b中前j位最长公共子序列个数
17
18 int main() {20     cin>>a>>b;
21     la=a.length()-1;
22     lb=b.length()-1;
23     a=‘ ‘+a;
24     b=‘ ‘+b;
25     for(int i=0;i<=max(la,lb);++i)
26         g[0][i]=g[i][0]=1;
27
28     for(int i=1;i<=la;++i)
29          for(int j=1;j<=lb;++j) {
30              if(a[i]==b[j]) {
31                  f[i][j]=f[i-1][j-1]+1;
32                  g[i][j]=g[i-1][j-1]%mod;
33                  if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod;
34                  if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod;
35
36              }
37              else {
38                  f[i][j]=max(f[i-1][j],f[i][j-1]);
39                  if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod;
40                  if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod;
41                  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)%mod;
42
43              }
44         }
45     printf("%d\n%d\n",f[la][lb],g[la][lb]);
46     return 0;
47 }
时间: 2024-10-20 10:53:28

【DP】最长公共子序列的相关文章

POJ 2250 Compromise (DP,最长公共子序列)

Compromise Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6440 Accepted: 2882 Special Judge Description In a few months the European Currency Union will become a reality. However, to join the club, the Maastricht criteria must be fulfille

hdu 1159 Common Subsequence(dp 最长公共子序列问题LCS)

最长公共子序列问题(LCS,Longerst Common Subsequence). s1s2……si+1和t1t2……tj+1的公共子序列可能是: ①当si+1=tj+1时,在s1s2……si+1和t1t2……tj+1的公共子序列末尾追加一个. ②s1s2……si+1和t1t2……tj的公共子序列 ③s1s2……si和t1t2……tj+1的公共子序列 所以易得到递推关系dp[i+1][j+1]=  max{ dp[i][j]+1 , dp[i][j+1] , dp[i+1][j]) }  

POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 56150   Accepted: 19398 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a

poj1159--Palindrome(dp:最长公共子序列变形 + 滚动数组)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 53414   Accepted: 18449 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a

hdu1159 dp(最长公共子序列)

题意:给两个字符串,求这两个字符串的最长公共子序列的长度 因为之前集训的时候做过,所以现在即使会做也并不是什么稀奇的事,依旧为了自己的浅薄感到羞愧啊``` 解法就是通过两个字符串的每个字符互相比较,根据比较情况相同与否确定递推关系: dp [ i + 1 ] [ j + 1 ] 表示匹配到 a 字符串的第 i 个字符和 b 字符串的第 j 个字符时的最大匹配数,由于读字符串的时候我是从下标 0 读起的,但我需要用 dp [ 0 ] ,所以就都是加了一,否则也可以读入的时候直接从 a + 1 和

经典dp 最长公共子序列

首先,说明一下子序列的定义…… 一个序列A={a1,a2,a3,...,an},从中删除任意若干项,剩余的序列叫A的一个子序列. 很明显(并不明显……),子序列……并不需要元素是连续的……(一开始的时候思维总是以为元素是连续的,好傻啊……) 然后是公共子序列…… 如果C是A的子序列,也是B的子序列,那么C是A和B的公共子序列…… 公共子序列一般不止一个,最长的那个就是最长公共子序列,当然也可能不止一个…… 煮个栗子…… A={1,3,6,9,5,4,8,7},B={1,6,3,4,5,7} {1

UVa 10066 Twin Towers (DP 最长公共子序列)

题意  求两串数字最长公共子序列的长度 裸的lcs没啥说的 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=105; int a[maxn],b[maxn],d[maxn][maxn],na,nb; void lcs() { memset(d,0,sizeof(d)); for(int i=1; i<=na; ++i) for(in

newcoder 练习赛17 B 好位置 dp 最长公共子序列

链接:https://www.nowcoder.com/acm/contest/109/B来源:牛客网 好位置 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format: %lld 题目描述 给出两个串s和x 定义s中的某一位i为好的位置,当且仅当存在s的子序列 满足y=x且存在j使得i=kj成立. 问s中是否所有的位置都是好的位置. 输入描述: 一行两个字符串s,x,这两个串均由小写字母构成.1 <= |s|, |x|

hdu 1159 经典dp最长公共子序列

背景:上次比赛就没有做出来,回来根据实际意义半天也想不出如何dp,结果从猜转移方程入手,竟然想对了!开始想把空间优化到一维数组,没有想到要用同维度左边的值wa了. 思路: dp[i][j]=max{max[i-1][j],max[i][j-1],max[i-1][j-1]+(a[i] == b[j])} //dp[i][j]定以为,a串的前i个字符和b串的前b个字符的最大字串和,为选a串的第i个字符而不选b串的第j个字符,不选a串的第i个字符而选b串的第j个字符,既选a串的第i个字符又选b串的第

简单Dp----最长公共子序列,DAG最长路,简单区间DP等

/* uva 111 * 题意: * 顺序有变化的最长公共子序列: * 模板: */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100]; int mu[100]; int Dp[100][100]; int main() { int n,x; scanf("%d", &n