hdu 1159 解题报告 (冷静讨论分析+然后得到推导公式)(51nod 1006) hdu 1503(最长公共子序列+标记路径)

这题与hdu 2604一样都是都需要通过讨论得到推导公式,而推导公式的得来便是解题的关键

hdu 1159

Common Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 48674    Accepted Submission(s): 22392


 

Problem 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. 
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. 

 

Sample Input

 

abcfbc abfcab programming contest abcd mnp

 

Sample Output

 

4 2 0

 

Source

Southeastern Europe 2003

 

Recommend

Ignatius


这道题是要找出两个字符串(s1和s2)中最长公共子序列

首先:

    建立二维数组dp[ i ][ j ]  -----它代表的是字符串s1前i个字符与字符串s2前j个字符的最长公共子序列

接着是讨论:

    分为两种情况:

  1.    当s1[ i ]==s2[ j ]时,那么dp[ i ][ j ]就等于dp[ i-1][ j-1]加上1
  2.    当s1[ i ]不等于s2[ j ]时,那么dp[ i ][ j ]就等于s1前i个字符与s2前j-1个字符的最长公共子序列,或者s1前i-1个字符与s2前j个字符的最长公共子序列,具体哪一个,取两者最大值即可 (有可能会想可不可以是i-1与j-1呢?因为它的大小肯定不会大于i-1与j的大小,因为毕竟后者比前者多了个s2[ j ]这个字符嘛,因此没有必要跳一级)

将上面的步骤用代码实现:

for(int i=1;i<=a_len;i++)
            for(int j=1;j<=b_len;j++)
                if(a[i-1]==b[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

这题求的是数值,如果要求输出最长公共子序列中的一个呢(51nod 1006)

     就是打印路径:一种是用与dp相反的方向输出所经过的路径:链接一链接二,链接二比较好理解些
                               另一种是在dp时做标记,然后在通过标记一步一步找到路径:链接三


代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1e3+10;

int dp[maxn][maxn];
int ans[maxn];
int main()
{
    char a[maxn],b[maxn];
    while(scanf("%s%s",a,b)==2)
    {
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        int a_len=strlen(a);
        int b_len=strlen(b);
        for(int i=1;i<=a_len;i++)
            for(int j=1;j<=b_len;j++)
                if(a[i-1]==b[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;

                else
                   {
                       dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

                   }
        int i=a_len;
        int j=b_len;
        int k=dp[i][j];
        char lcs[1001]={'\0'};
        while(i&&j)
        {
            if(a[i-1]==b[j-1])
            {
                lcs[--k]=a[i-1];
                i--;
                j--;
            }
            else if(dp[i-1][j]>dp[i][j-1]) i--;
            else j--;
        }
        printf("%s\n",lcs);
    }
    return 0;
}








hdu 1503 

这题调试了好久,终于给我调出来了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1e3+10;

int dp[maxn][maxn];

int main()
{
    char a[maxn],b[maxn];
    while(scanf("%s%s",a,b)==2)
    {
        memset(dp,0,sizeof(dp));
        int a_len=strlen(a);
        int b_len=strlen(b);
        for(int i=1;i<=a_len;i++)
            for(int j=1;j<=b_len;j++)
                if(a[i-1]==b[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);


        int i=a_len;
        int j=b_len;
        int k=dp[i][j];
        int as[1001];
        int bs[1001];
        char lcs[1001]={'\0'};
        while(i&&j)
        {
            if(a[i-1]==b[j-1])
            {
                lcs[--k]=a[i-1];
                as[k]=i-1;
                bs[k]=j-1;
                i--;
                j--;
            }
            else if(dp[i-1][j]>dp[i][j-1]) i--;
            else j--;
        }

        char lcs2[1001]={'\0'};
        int ans=0;
        int astart=0;
        int bstart=0;
        k=dp[a_len][b_len];
        for(int i=0;i<k;i++)
        {
            for(int j=astart;j<as[i];j++)
            {
                lcs2[ans++]=a[j];

            }
            astart=as[i]+1;
            for(int j=bstart;j<bs[i];j++)
            {
                lcs2[ans++]=b[j];

            }
             bstart=bs[i]+1;
            lcs2[ans++]=lcs[i];

        }
        for(int i=astart;i<a_len;i++)
        lcs2[ans++]=a[i];
        for(int i=bstart;i<b_len;i++)
        lcs2[ans++]=b[i];



        printf("%s\n",lcs2);
    }
    return 0;
}







猜你喜欢

转载自blog.csdn.net/weixin_42373330/article/details/81987017