HDU1423&ZOJ2432 - Greatest Common Increasing Subsequence(LCIS最长公共上升子序列模板)

41 篇文章 0 订阅

题目链接HDUhttp://acm.hdu.edu.cn/showproblem.php?pid=1423(不需要输出路径) ZOJhttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1432(输出路径)

【题意】求两个序列的最长公共子序列,经典算法;(注意:HDU输出格式和ZOJ类似,需要每两个case之间加一行空行)

【分析】

(1)n^3模板

dp[i][j]表示序列a前i个和序列b前j个字符,并且以b[j]作为LCIS序列的末尾的LCIS的长度
转移方程
1) dp[i][j] = dp[i-1][j] (a[i] != b[j])
//a[i] != a[j]时不满足两个序列公共,所以不会增加长度,又因为dp[][]是以b[j]作为结尾的新序列下的长度,所以直接等于dp[i-1][j]的值
2) dp[i][j] = {dp[i-1][k] | 1 <= k < j} (a[i] == b[j])
//只有a[i] == b[j]时才会有可能使得长度增加,然后对b[](其实主要是对a[k] == b[m](k < j)的序列)进行LIS就可以了

(2)n^2模版

看看LIS中的条件:b[k]<b[j](1<=k<=j-1)&&a[i]==b[j]  可以推出a[i]>b[j](这里的j相当于下个循环的枚举的k),用一个maxn变量来记录dp[i-1][1~j]的最大值,可以省去LIS中的每次都重复查找最大值,这样可以把复杂度降低一维。

(3)n^2滚动数组模板

因为dp[i][..]使用的都是上一次的dp[i-1][...],当然可以像01背包那样用滚动数组优化,第二个循环不是倒序,因为这里有点像完全背包那样,本次循环更新之后,还可以在本次基础上再更新;使用滚动数组就没办法输出路径了,因为路径需要以前的状态才能输出。

 

【AC代码(n^3)ZOJ】720ms

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 510
struct NODE{//记录路径
    int x, y;
}f[MAXN][MAXN];
int a[MAXN], b[MAXN], dp[MAXN][MAXN], ex, ey;

void pt(int i, int j)
{
    if (!i || !j)
        return;
    int x = f[i][j].x, y = f[i][j].y;
    pt(x,  y);
    if (dp[x][y]+1 == dp[i][j])
    {
        printf ("%d", b[j]);
        if (i != ex && j != ey)
            printf (" ");
    }
}
int main ()
{
    #ifdef SHY
        freopen("e:\\1.txt", "r", stdin);
    #endif
    int t;
    scanf ("%d%*c", &t);
    while(t--)
    {
        int na, nb, ans = 0;
        ex = 0, ey = 0;
        scanf ("%d%*c", &na);
        for (int i = 1; i <= na; i++)
            scanf ("%d%*c", &a[i]);
        scanf ("%d%*c", &nb);
        for (int i = 1; i <= nb; i++)
            scanf ("%d%*c", &b[i]);
        memset(dp,0,sizeof(dp));
        memset(f,0,sizeof(f));
        for (int i = 1; i <= na; i++)
        {
            for (int j = 1; j <= nb; j++)
            {
                if (a[i] == b[j])
                {
                    dp[i][j] = 1;
                    for (int k = 1; k < j; k++)
                    {
                        if (b[k] < b[j] && dp[i][j] < dp[i-1][k]+1)
                            dp[i][j]= dp[i-1][k]+1, f[i][j].x = i-1,f[i][j].y = k;
                    }
                    if (ans < dp[i][j])
                        ans = dp[i][j], ex = i, ey = j;
                }
                else
                    dp[i][j] = dp[i-1][j], f[i][j].x = i-1, f[i][j].y = j;
            }
        }
        printf ("%d\n", ans);
        pt(ex,ey);
        printf ("\n");
        if (t)
            printf ("\n");
    }
    return 0;
}


 【n^2算法ZOJ】30ms//利用了下标1开始,所以下标为0的一直不会被改变始终是初始化中的0

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 503
struct NODE{
    int x, y;
}f[MAXN][MAXN];
int a[MAXN], b[MAXN], dp[MAXN][MAXN], ex, ey;


void pt(int i, int j)
{
    if (!i || !j)
        return;
    int x = f[i][j].x, y = f[i][j].y;
    pt(x,  y);
    if (dp[x][y]+1 == dp[i][j])
        printf ("%d ", b[j]);
}
int main ()
{
    #ifdef SHY
        freopen("e:\\1.txt", "r", stdin);
    #endif
    int t;
    scanf ("%d%*c", &t);
    while(t--)
    {
        int na, nb, ans = 0;
        ex = 0, ey = 0;
        scanf ("%d%*c", &na);
        for (int i = 1; i <= na; i++)
            scanf ("%d%*c", &a[i]);
        scanf ("%d%*c", &nb);
        for (int i = 1; i <= nb; i++)
            scanf ("%d%*c", &b[i]);
        for (int i = 1; i <= na; i++)
        {
            int maxn = 0, x = 0, y = 0;
            for (int j = 1; j <= nb; j++)
            {
                if (a[i] == b[j])
                {
                    dp[i][j] = maxn+1;
                    f[i][j].x = x, f[i][j].y = y;
                    if (ans < dp[i][j])
                        ans = dp[i][j], ex = i, ey = j;
                }
                else
                {
                    dp[i][j] = dp[i-1][j], f[i][j].x = i-1, f[i][j].y = j;
                    if (a[i] > b[j] && maxn < dp[i-1][j])
                        maxn = dp[i-1][j], x = i, y = j;
                }
            }
        }
        printf ("%d\n", ans);
        pt(ex,ey);
        printf ("\n");
        if (t)
            printf ("\n");
    }
    return 0;
}

【n^2(滚动数组)HDU】0ms

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 503
int a[MAXN], b[MAXN], dp[MAXN];

int main ()
{
    #ifdef SHY
        freopen("e:\\1.txt", "r", stdin);
    #endif
    int t;
    scanf ("%d%*c", &t);
    while(t--)
    {
        int na, nb, ans = 0;
        scanf ("%d%*c", &na);
        for (int i = 1; i <= na; i++)
            scanf ("%d%*c", &a[i]);
        scanf ("%d%*c", &nb);
        for (int i = 1; i <= nb; i++)
            scanf ("%d%*c", &b[i]);
        memset(dp,0,sizeof(dp));
        for (int i = 1; i <= na; i++)
        {
            int maxn = 0;
            for (int j = 1; j <= nb; j++)
            {
                if (a[i] == b[j])
                {
                    dp[j] = maxn+1;
                    if (ans < dp[j])
                        ans = dp[j];
                }
                else if (a[i] > b[j] && maxn < dp[j])
                    maxn = dp[j];
            }
        }
        printf ("%d\n", ans);
        if (t)
            printf ("\n");
    }
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值