码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】LCIS

时间:2019-06-01 19:35:56      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:splay   alt   pen   void   ace   ant   show   题目   play   

题目描述

  给定两个整数序列,写一个程序求它们的最长上升公共子序列。

 

输入格式

  每个序列用两行表示,第一行是长度L,第二行是该序列。

输出格式

  在第一行,输出该LCIS的长度。第二行,输出该LCIS。

 

输入样例

5

1 4 2 5 -12

4

-12 1 2 4

 

输出样例

2

1 4

 

题解

  表面上看起来是个$O(n^{4})$,但实际上可以优化到$O(n^{2})$(貌似还可以用树状数组优化到$O(nlogn)$)

  我们设$dp[i][j]$为以$a_{1}$到$a_{i}$中的一个数和$b_{j}$为结尾的LCIS,容易得到$dp[i][j] = \underset{1 \leqslant k < j}{max} \left \{ dp[j - 1][k] + 1 \right \}$。

  其实我们可以在枚举$i$、$j$的时候顺便维护$\underset{1 \leqslant k < j}{max} \left \{ dp[j - 1][k] + 1 \right \}$,这样就把时间复杂度降到$O(n^{2})$了。

  观察方程,其实我们第一位只会用到$i - 1$和$i$,这里又可以用滚动数组优化。

技术图片
#include <iostream>

#define MAX_N (500 + 5)
#define MAX_M (500 + 5)

using namespace std;

int n, m;
int a[MAX_N], b[MAX_M];
int dp[MAX_M];
int p[MAX_M];
int ans;

void LCIS(int x)
{
    if(p[x]) LCIS(p[x]);
    cout << b[x] << " ";
    return;
}

int main()
{
    cin >> n;
    for(register int i = 1; i <= n; ++i)
    {
        cin >> a[i];
    }
    cin >> m;
    for(register int i = 1; i <= m; ++i)
    {
        cin >> b[i];
    }
    int pos = 0, tmp;
    for(register int i = 1; i <= n; ++i)
    {
        tmp = 0;
        for(register int j = 1; j <= m; ++j)
        {
            if(a[i] > b[j] && dp[j] > dp[tmp]) tmp = j;
               if(a[i] == b[j])
            {
                dp[j] = dp[tmp] + 1;
                p[j] = tmp;
            }
        }
    }
    for(register int i = 1; i <= m; ++i)
    {
        if(dp[i] > dp[pos]) pos = i;
    }
    cout << dp[pos] << "\n";
    if(dp[pos]) LCIS(pos);
    return 0;    
}
参考程序

 

【题解】LCIS

标签:splay   alt   pen   void   ace   ant   show   题目   play   

原文地址:https://www.cnblogs.com/kcn999/p/10960562.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!