dp lis的基本解法以及二分优化和树状数组优化

lis基本解法

O(n^2)

for(int i = 0;i < n;i++)
	for(int j = i+1;j < n;j++)
		if(a[i] < a[j]) dp[j] = max(dp[i]+1,dp[j]);

课设利用lis解决合唱队形,直接基本O(n^2)莽过。(洛谷P1091的100的数据n方轻松莽过。。。

//
//  main.cpp
//  sing
//
//  Created by 陈冉飞 on 2019/12/10.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#define maxn 10010
int a[maxn],n,dp1[maxn],dp2[maxn],ans;
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))

int main(int argc, const char * argv[]) {
//    while (~scanf("%d",&n)) {
    scanf("%d",&n);
        cl(a,0);cl(dp1, 0);cl(dp2, 0);
        for (int i = 0; i < n; i++) {scanf("%d",&a[i]);dp1[i] = dp2[i] =1;}
        for (int i = 1; i < n; i++)
            for (int j = 0; j < i; j++)
                if (a[i] > a[j]) dp1[i] = max(dp1[j]+1,dp1[i]);
        for (int i = n-2; i >=0; i--)
            for (int j = n-1; j >i; j--)
                if (a[j] < a[i]) dp2[i] = max(dp2[j]+1,dp2[i]);
        for (int i = 0; i < n; i++)
            if (ans < (dp1[i]+dp2[i])) ans = dp1[i]+dp2[i];
    printf("\n\n");
    for ( int i = 0; i < n; i++) printf("%d ",dp1[i]);
    printf("\n\n");
        printf("%d\n",n-ans+1);
//    }
    return 0;
}

好了。言归正传,lis利用二分nlogn……
用一个数组其实这个数组没有什么特殊的含义,来记录对应索引处的长度的lis的最小末尾,利用这个末尾可以插入数据
插入数据利用二分插入,插入到合适的位置。
二分插入logn,n个数,所以最后是nlogn

//
//  main.cpp
//  binary_lis
//
//  Created by 陈冉飞 on 2019/12/15.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#define maxn 10010
int a[maxn],ans[maxn],n,len;
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))

int binary(int t){
    int l = 0,r = len,mid;
    while (l < r) {
        mid = (l+r)>>1;
        if (a[t] < ans[mid]) r = mid;
        else l = mid+1;
    }
    return l;
}

int binary_lis(){
    len = 1;ans[1] = a[1];
    for (int i = 2; i <= n; i++)
        if (a[i] > ans[len]) ans[++len] = a[i];
        else ans[binary(i)] = a[i];
//    for (int i = 1; i <= len; i++) printf("%d ",ans[i]);
    return len;
}

int main(int argc, const char * argv[]) {
    while (~scanf("%d",&n)) {
        // init
        cl(a,0);
        for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
        printf("%d",binary_lis());
    }
    return 0;
}

利用二分没有可扩展性,也就是只能算出整个长度的最大递增。
然后通过树状数组可以得到整个的每个段的lis

//
//  main.cpp
//  tree_lis
//
//  Created by 陈冉飞 on 2019/12/15.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
#define maxn 10010
int a[maxn],b[maxn],dp1[maxn],f[maxn],n,t,ans,dp2[maxn];
#include <algorithm>
#define lowbit(x) x&-x

void modify(int x,int p){
    for (; x <= t ; x += lowbit(x)) f[x] = max(f[x],p);
}

int get_max(int x){
    int tem = 0;
    for (; x; x -= lowbit(x)) tem = max(tem,f[x]);
    return tem;
}

int main(int argc, const char * argv[]) {
    while (~scanf("%d",&n)) {
        for (int i = 1; i <= n; i++) scanf("%d",&a[i]),b[i] = a[i];
        sort(b+1,b+n+1);
        t = unique(b+1,b+n+1)-b-1;
        for (int i = 1; i <= n; i++) a[i] = lower_bound(b+1,b+t+1,a[i])-b;
        for (int i = 1; i <= n; i++) {
            dp1[i] = get_max(a[i]-1)+1;
            ans = max(ans,dp1[i]);
            modify(a[i],dp1[i]);
        }
        for (int i = 1; i <= n; i++) printf("%d ",dp1[i]);
        printf("%d\n",ans);
    }
    return 0;
}
发布了95 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43345204/article/details/103552780