ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SDUT 1008 最长公共子序列

2019-06-01 17:52:15  阅读:223  来源: 互联网

标签:字符 数组 index int ret SDUT 1008 序列


最长公共子序列

  该题解参考这位博主https://blog.csdn.net/weyuli/article/details/9309121,我写这篇随笔只是为了解释一下这位博主写的代码,因为代码的注释很少,若是有跟我一样的新人怕是要耗费很长时间去理解题意,借此机会说说我对这个题的思路,并解释该博主的部分代码

内容:

  从一个给定的串中删去(不一定连续地删去)0个或0个以上的字符,剩下地字符按原来顺序组成的串。例如:“ ”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子序列。(例子中的串不包含引号。)

编程求N个非空串的最长公共子序列的长度。限制:2<=N<=100;N个串中的字符只会是数字0,1,…,9或小写英文字母a,b,…,z;每个串非空且最多含100个字符;N个串的长度的乘积不会超过30000。

 

  此题的理解还需了解如何求两字符序列的最长公共字符子序列,若不懂请自行百度学习, 题目练习题号SDUT 2080。

  题目中有一句话:N个串的长度的乘积不会超过30000,这个地方告诉了我们数据的规模并且还强调了N个串长度的乘积,这里就要提一下,在求两字符序列的最长公共字符子序列这个问题中,我们为了方便理解,会画一个m * n的表格(m代表字符串x的长度,n代表字符串y的长度,x,y为任意两字符序列)来观察公共字符个数,两字符序列的最长公共字符子序列问题还可以看成二维公共子序列问题,因为解题的时候我们会建立一个二维数组。

  该题可以看成一个多维字符求最长公共子序列,但是题目说:N个子符串的乘积不会超过30000。这里我们就可以把这道多维问题转化为一个一维问题,参照求两字符序列的最长公共字符子序列问题把本该建立的多维表格给转化为一维数组,数组的下标的含义可以看成:index = x1 * x2 * x3 * …… * xi。每一个index都对应着唯一的情况,即:多维字符串的长度为x1,x2,x3……xi时是否有公共字符。

  具体思路如下:

  建立一个二维字符数组保存字符,建立一个一维数组len来保存每一个字符数组的长度,一维数组L来保存多维字符数组长度的动态变化,用于求index(这部分请结合下面的代码利于理解),我们从每一个字符数组的末尾开始匹配,若都相等则把每一个多维数组长度L减一(所以我称它为动态长度数组),所以最长长度ret = DP(L) + 1;若只要有一个不同,则开始枚举每一种情况,详细请看代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; char a[110][110]; int dp[30000 + 10];
int len[110]; int n; int DP( int *x )
{
    int i, j, index, ret;
    for( i = 1; i <= n; i++ )
    {
        if( x[i] == 0 )
        {
            return 0;
        }
    }     for( index = x[n] - 1, i = n - 1; i >= 1; i-- )
    {
        index = index * len[i] + x[i] - 1; //转化为一维数组
    }     if( dp[index] >= 0 )
    {
        return dp[index];
    }     //从每个字符串的末尾开始匹配
    for( i = 2; i <= n; i++ )
    {
        if( a[1][x[1] - 1] != a[i][x[i] - 1] )
        {
            break;
        }
    }
    if( i > n )
    {
        for( j = 1; j <= n; j++ )
        {
            x[j]--;
        }
        ret = DP(x) + 1;
        for( j = 1; j <= n; j++ )
        {
            x[j]++;
        }
    }
    else
    {
        ret = 0;
        int t;
        //开始枚举每一种情况
        for( j = 1; j <= n; j++ )
        {
            x[j]--;
            t = DP( x );
            ret = max( ret, t );
            x[j]++;
        }
    }
    dp[index] = ret;
    return ret;
} int main()
{
    int T;
    int L[110];
    scanf("%d", &T);
    while( T-- )
    {
        scanf("%d", &n);
        for( int i = 1; i <= n; i++ )
        {
            scanf("%s",a[i] );
            len[i] = L[i] = strlen( a[i] );
        }
        memset( dp, -1, sizeof(dp) );
        printf("%d\n", DP( L ) );
    }
    return 0;
}

标签:字符,数组,index,int,ret,SDUT,1008,序列
来源: https://www.cnblogs.com/Naive-and-pure/p/10960355.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有