Common Subsequence-最长公共子序列

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. 
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. 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. 

Input

abcfbc abfcab
programming contest 
abcd mnp

Output

4
2
0

Sample Input

abcfbc abfcab
programming contest 
abcd mnp

Sample Output

4
2
0

在刚开始学习这一部分的时候,在别人的博客里面有看到这个图,当时看的时候特别懵,不过后来自己推导一遍,发现其实跟刚开始学动规的背包问题差不多,想法就是在每次交换的时候尽可能的贪,就是要让每一次的计算得到的数字的值是最大的。。

问题被分解成了三部分:

1、当前比较的两个字母相等,在我看来,动规是在前面结果的基础上的叠加,也就是这个时候要用前一个字母的结果进行+1

2、当前比较的两个字母不相等(就拿图中的横竖数字来说吧)

    2.1、如果当前坐标的前一个纵坐标的数大于前一个横坐标的数,这个数就是前一个纵坐标的数,以满足当前值的最大性。

    2.2、如果当前坐标的前一个纵坐标的数小于前一个横坐标的数,这个数就是前一个横坐标的数,以满足当前值的最大性。

 

按照这个方法,很容易把本题给解出来,我就不给出求最长子序列的模板了,可以通过本题的AC代码提取,不过要注意,本题有一个坑点,就是没有给出数据的取值范围!

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
char a[10005],b[10005];
char a1[10005],b1[10005];
int dp[1005][1005];
int main()
{
    while(~scanf("%s %s",a,b))
    {
        for(int i=0;i<=1004;++i)
        {
            for(int j=0;j<=1004;++j)
                dp[i][j]=0;
        }
        int l1=strlen(a);
        int l2=strlen(b);
        for(int i=1;i<=l1;++i)
        {
            a1[i]=a[i-1];
        }
        for(int i=1;i<=l2;++i)
        {
            b1[i]=b[i-1];
        }
        for(int i=1;i<=l1;++i)
        {
            for(int j=1;j<=l2;++j)
            {
                if(a1[i]==b1[j])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else if(dp[i][j-1]>dp[i-1][j])
                {
                    dp[i][j]=dp[i][j-1];
                }
                else
                {
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        printf("%d\n",dp[l1][l2]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值