POJ 2127 Greatest Common Increasing Subsequence DP 最长公共上升子序列

题意:求最长公共上升子序列。

思路1:O(n^3) 算法

 

用dp[i][j]为a串匹配到i,b串匹配到j时的最长公共上升子序列的长度。

状态转移方程如下:

dp[i][j] = max(dp[k][t]+1) (1<= k < i && 1 <= t < j && a[i] == b[j] && a[k] < a[i] && b[t] < b[j])
dp[i][j] = max(dp[k][t])   (1<= k <= i && 1 <= t <= j && a[i] != b[j]) (k == i 与 t == j 不同时取到)

复杂度:O(n^4) ,TLE,需要优化。

优化:

我们以a串为基准,重新定义dp[i][j] :以a[i]为基准匹配串末尾时(a[i]必选),匹配到b[j]时的最长公共上升子序列的长度

状态转移方程:

dp[i][j] = dp[i][j-1] (a[i] != b[j])

dp[i][j] = max{ dp[k][j-1] } (1 <= k < i && a[i] == b[j] && a[k] < a[i])

通过这样的定义我们保证了,对于任何dp[i][j], dp[i][j]里面存放的是已当前a[i]为匹配的串的最后一个元素时的最大长度。

代码:

View Code
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[505], b[505], dp[505][505];
int max(int a, int b) { return a > b ? a : b; }
void print(int x, int y) // 递归输出路径
{
    if(x < 1 || y < 1) return;
    if(a[x] != b[y])
        print(x, y-1);
    else
    {
        for(int i = x-1; i >= 1; i--)
            if( a[i] < a[x] && dp[i][y] + 1 == dp[x][y])
            {    print(i, y); break; } 
        printf("%d ", a[x]);
    }
}
int n, m;
int main()
{
    int i, j, k;
    while( ~scanf("%d", &n))
    {
        for(i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        scanf("%d", &m);
        for(i = 1; i <= m; i++)
            scanf("%d", &b[i]);
        memset(dp, 0, sizeof(dp));
        for(i = 1; i <= n; i++)
            for(j = 1; j <= m; j++)
                if(a[i] == b[j])
                {
                    for(k = 0; k < i; k++) // 注意循环不能倒过来,想一想为什么
                        if(a[k] < a[i] && dp[i][j] < dp[k][j-1] + 1)
                            dp[i][j] = dp[k][j-1] + 1;
                    if(!dp[i][j]) dp[i][j] = 1;
                }
                else dp[i][j] = dp[i][j-1];
        int ans = 0, k = 0;
        for(i = 1; i <= n; i++)
            if(ans < dp[i][m]) ans = dp[i][m], k = i;
        printf("%d\n", ans);
        print(k, m);
        puts("");
    }
    return 0;
}
/*

 3 2

 1 2

 3 2 1 5

 1 2 3 5
*/

 

思路2:O(n^2)算法

 

 

 

posted @ 2012-11-16 23:12  To be an ACMan  Views(291)  Comments(0)    收藏  举报