LIS nlogn优化以及路径输出

LIS(最长上升子序列)分析:

  sequence : -7 10  9  2  3  8  8  1
    temp LIS :
    position :

    sequence :(-7)10  9  2  3  8  8  1
    temp LIS : -7
    position :  1       // -7 在 LIS 的第一個位置

    sequence : -7(10) 9  2  3  8  8  1
    temp LIS : -7 10
    position :  1  2    // 10 在 LIS 的第二個位置,以此類推。

    sequence : -7 10 (9) 2  3  8  8  1
    temp LIS : -7  9
    position :  1  2  2
    /* 9 成為 LIS 的潛力比 10 大, 所以以 9 代替 10 */

    sequence : -7 10  9 (2) 3  8  8  1
    temp LIS : -7  2
    position :  1  2  2  2
    /* 2 成為 LIS 的潛力比 9 大, 所以以 2 代替 9 */

    sequence : -7 10  9  2 (3) 8  8  1
    temp LIS : -7  2  3
    position :  1  2  2  2  3

    sequence : -7 10  9  2  3 (8) 8  1
    temp LIS : -7  2  3  8
    position :  1  2  2  2  3  4

    sequence : -7 10  9  2  3  8 (8) 1
    temp LIS : -7  2  3  8
    position :  1  2  2  2  3  4  4
    /* 8 成為 LIS 的潛力比 8 大, 所以以 8 代替 8 */

    sequence : -7 10  9  2  3  8  8 (1)
    temp LIS : -7  1  3  8
    position :  1  2  2  2  3  4  4  2
    /* 1 成為 LIS 的潛力比 2 大, 所以以 1 代替 2 *

路径输出的话就是倒序输出(dp的长度就是最长子序列的长度),从len到1,t–,找到第一个pos[i]=t的地方输出。

  sequence : -7 10  9  2  3  8 (8) 1
    position :  1  2  2  2  3  4 (4) 2
    LIS      :  -  -  -  8
    /* search 4th, 8 is fourth LIS element */

    sequence : -7 10  9  2 (3) 8  8  1
    position :  1  2  2  2 (3) 4  4  2
    LIS      :  -  -  3  8
    /* search 3rd, 3 is third LIS element */

    sequence : -7 10  9 (2) 3  8  8  1
    position :  1  2  2 (2) 3  4  4  2
    LIS      :  -  2  3  8
    /* search 2nd, 2 is second LIS element */

    sequence :(-7)10  9  2  3  8  8  1
    position : (1) 2  2  2  3  4  4  2
    LIS      : -7  2  3  8
    /* search 1st, -7 is first LIS element */

下面是代码(利用了STL中自带的二分函数,lower_bound(找到第一个大于a[i]的位置))

#include<cstdio>
#include<cmath>
#include<cstring> 
#include<algorithm>
using namespace std;

const int maxn = (int)1000 + 10;
int a[maxn],dp[maxn];
int pos[maxn];//记录位置 
int list[maxn];//记录路径 
int n;
int main(){
    scanf("%d",&n);
    memset(a,0,sizeof(a));
    memset(dp,0,sizeof(dp));
    for(int i = 1;i<=n;i++) scanf("%d",&a[i]);


    int len=1;
    int po = 1;
    dp[1] = a[1],pos[1]= 1;
    for(int i = 2;i<=n;i++){
        if(a[i]>dp[len]){
            dp[++len] = a[i];
            pos[++po] = len;//用来记录从a[i]中1到n每个位置的在dp中的位置 
        }                   //a[i]   -7 10 9 2 3 8 8 1 
        else{               //pos[j]  1  2 2 2 3 4 4 2
            int cnt = lower_bound(dp+1,dp+len+1,a[i]) - dp;
            dp[cnt] = a[i];
            pos[++po] = cnt;
        }
    }

    //for(int i = 1;i<=n;i++) printf("%d",pos[i]);
    int t = len;
    for(int i = n;i>=1;i--){
        if(pos[i] == t){
            list[t--] = a[i];
        }
        if (t<1) break; 
    }

    for(int i = 1;i<=len;i++) printf("%d\n",list[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Lj_victor/article/details/81603657
lis