hdu 1423 Greatest Common Increasing Subsequence

33 篇文章 0 订阅

Greatest Common Increasing Subsequence

hdu 1423 GCIS (n^2)

省赛的时候,这个题目看了良久,都没想到O(n^2)的算法。后来苏犇看到GCIS的时候就让看模版,然后在吉大的模版上看到了这个

然后我们就顺利的1Y.我又看了一下这个题目,找了好多博客(不是挂了,就是讲的很不清楚)。。然后看到了http://www.tyvj.cn/bbs/Discuss_Show.aspx?id=30583这个博客,博主讲的很给力。

这个题目的状态与LCS的状态差不多,只不过加了些约束dp[i][j]表示a串走到第i个数字,b串走到第j个数字,然后以b串的第j个数字为最终的最长公共递增子序列的长度这样我们就可以直接搞出方程了:

dp[i][j] = dp[i - 1][j] if(a[i] != b[j])
dp[i][j] = max(dp[i - 1][k]) + 1 , 1 <= k < j && b[k] < a[i]

由方程其实我们很容易想到用滚动数组优化,在实现的时候由于在相等的时候b串第j个数字是固定的,所以我们可以很容易的在扫的时候直接计算出对应最大值。。

/*
    author    : csuchenan
    prog      : hdu 1423
    algorithm : Greatest Common Increase Subsequence O(n^2)
                dp[i][j] 以b串的j为终点的最长公共上升子序列的长度。
                dp[i][j] = dp[i - 1][j] if(a[i] != b[j]) 
                dp[i][j] = max(dp[i - 1][k]) + 1 , 1 <= k < j && b[k] < a[i] 
                由于递推的时候只涉及到i-1,所以我们可以直接用滚动数组优化
                详见程序
*/

#include <cstdio>
#include <cstring>
const int maxn = 550 ;

int dp[maxn] ;
int a[maxn]  ;
int b[maxn]  ;

int GCIS(int la , int lb){
    memset(dp , 0 , sizeof(dp)) ;
    int i , j , mx ;
    for(i = 1 ; i <= la ; i ++){
        for(mx = 0 , j = 1 ; j <= lb ; j ++){
            if(b[j] < a[i] && mx < dp[j]){
                mx = dp[j] ;
            }
            if(b[j] == a[i]){
                dp[j] = mx + 1 ;
            }
        }
    }
    for(i = 1 , mx = 0 ; i <= la ; i ++){
        mx = mx > dp[i] ? mx : dp[i] ;
    }
    return mx ;
}

int main(){
    int la , lb ;
    int Tcas ;
    scanf("%d" , &Tcas) ;
    while(Tcas--){
        scanf("%d" , &la) ;
        for(int i = 1 ; i <= la ; i ++){
            scanf("%d" , &a[i]) ;
        }

        scanf("%d" , &lb) ;
        for(int i = 1 ; i <= lb ; i ++){
            scanf("%d" , &b[i]) ;
        }

        printf("%d\n" , GCIS(la , lb)) ;
        if(Tcas)
            puts("") ;
    }
    return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值