您的位置:首页 > 产品设计 > UI/UE

(不连续)最大公共子序列POJ 1458Common Subsequence

2015-09-07 12:03 459 查看
Common Subsequence

Time Limit: 1000MS Memory Limit: 10000K

Total Submissions: 43639 Accepted: 17766

Description

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, …, xm > another sequence Z = < z1, z2, …, zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, …, ik > of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

Input

The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.

Output

For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

Sample Input

abcfbc abfcab

programming contest

abcd mnp

Sample Output

4

2

0

Source

Southeastern Europe 2003

问题描述

我们称序列 Z = < z1, z2, …, zk >是序列X = < x1, x2, …, xm >的子序列当且仅当存在严格上

升的序列< i1, i2, …, ik >,使得对j = 1, 2, … ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b,

c, f, b, c >的子序列。

现在给出两个序列X 和Y,你的任务是找到X 和Y 的最大公共子序列,也就是说要找

到一个最长的序列Z,使得Z 既是X 的子序列也是Y 的子序列。

输入数据

输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200 的字符串,表示

两个序列。两个字符串之间由若干个空格隔开。

输出要求

对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。

输入样例

abcfbc abfcab

programming contest

abcd mnp

输出样例

4

2

0

解题思路

如果我们用字符数组 s1、s2 存放两个字符串,用s1[i]表示s1 中的第i 个字符,s2[j]表示s2 中的第j 个字符(字符编号从1 开始,不存在“第0 个字符”),用s1i 表示s1 的前i个字符所构成的子串, s2j 表示s2 的前j 个字符构成的子串,MaxLen(i, j)表示s1i 和s2j 的最长公共子序列的长度,那么递推关系如下:

if( i ==0 || j == 0

{

MaxLen(i, j) = 0 //两个空串的最长公共子序列长度当然是0}

else if ( s1[i] == s2[j] ) MaxLen(i, j) = MaxLen(i-1, j-1 ) + 1;

else MaxLen(i, j) = Max( MaxLen(i, j-1), MaxLen(i-1, j));

MaxLen(i, j) = Max( MaxLen(i, j-1), MaxLen(i-1, j)) 这个递推关系需要证明一下。我们用反证法来证明,MaxLen(i, j)不可能比MaxLen(i, j-1)和MaxLen(i-1, j)都大。先假设MaxLen(i,j)比MaxLen(i-1, j)大。如果是这样的话,那么一定是s1[i]起作用了,即s1[i]是s1i 和s2j 的最长公共子序列里的最后一个字符。同样,如果MaxLen(i, j)比MaxLen(i, j-1)大,也能够推导出,s2[j]是s1i 和s2j 的最长公共子序列里的最后一个字符。即,如果MaxLen(i, j)比MaxLen(i, j-1)和MaxLen(i-1, j)都大,那么,s1[i]应该和s2[j]相等。但这是和应用本递推关系的前提—– s1[i]≠s2[j]相矛盾的。因此,MaxLen(i, j)不可能比MaxLen(i, j-1)和MaxLen(i-1, j)都大。MaxLen(i, j)当然不会比MaxLen(i, j-1)和MaxLen(i-1, j)中的任何一个小,因此,MaxLen(i, j) = Max( MaxLen(i, j-1), MaxLen(i-1, j)) 必然成立。

显然本题目的“状态”就是s1 中的位置i 和s2 中的位置j。“值”就是MaxLen(i, j)。状态的数目是s1 长度和s2 长度的乘积。可以用一个二维数组来存储各个状态下的“值”。本问题的两个子问题,和原问题形式完全一致的,只不过规模小了一点。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<iostream>
#define MAX_LEN 1000
using namespace std;
char sz1[MAX_LEN];
char sz2[MAX_LEN];
int aMaxLen[MAX_LEN][MAX_LEN];
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
while(scanf("%s%s",&sz1[1],&sz2[1])==2)
{
int nLength1=strlen(sz1+1),nLength2=strlen(sz2+1),i,j;
for(i=0;i<=nLength1;i++) aMaxLen[i][0]=0;
for(j=0;j<=nLength2;j++) aMaxLen[0][j]=0;
for(i=1;i<=nLength1;i++)
{
for(j=1;j<=nLength2;j++)
{
if(sz1[i]==sz2[j]) aMaxLen[i][j]=aMaxLen[i-1][j-1]+1;
else
aMaxLen[i][j]=(aMaxLen[i][j-1]>aMaxLen[i-1][j]?aMaxLen[i][j-1]:aMaxLen[i-1][j]);
}
}
printf("%d\n",aMaxLen[nLength1][nLength2]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  子序列 dp poj