poj-1631-Bridging signals-最长上升序列(LIS)

额(⊙o⊙)…    先放题目链接

题目传送门:https://vjudge.net/problem/POJ-1631


题目就是求最长上升序列(自己想想吧!)


lis是啥——>一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).


测试数据(题目上给的太扯犊子了)


Sample Input
4
6
4 2 6 3 1 5
10
2 3 4 5 6 7 8 9 10 1
8
8 7 6 5 4 3 2 1
9
5 8 9 2 3 1 7 4 6
Sample Output
3
9
1
4


这样多好看,真是的!^_^


首先


我们来看一种方法:大致运用dp来做的


直接上代码,学过一点点dp的估计都看的懂!不懂就留言吧!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005

using namespace std;

int a[N];
int dp[N];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        int mmax = -1;
        for(int i = 1; i <= n; i++)
        {
            dp[i] = 1;
            for(int j = 1; j <= i; j++)
            {
                if(a[i] > a[j] && dp[i] < dp[j] + 1)
                    dp[i] = dp[j] + 1;
            }
            mmax = max(mmax, dp[i]);
        }
        printf("%d\n", mmax);
    }
    return 0;
}


估计会有人直接去提交,我可没说是ac的代码,这是tl的代码,其实一看,就知道超时 一个for和两个for嵌套,肯定的

(・ω・`ll),复杂度为n^2



换方法吧!先上代码^_^


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005

using namespace std;

int a[N];
int dp[N];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        int len = 1;
        dp[1] = a[1];
        for(int i = 2; i <= n; i++)
        {
            if(a[i] > dp[len])
            {
                len++;
                dp[len] = a[i];
                continue;
            }
            int l = 1, r = len;

            while(l <= r)
            {
                int mid = (l + r) / 2;

                if(dp[mid] > a[i])
                    r = mid - 1;
                else
                    l = mid + 1;
            }

            dp[l] = a[i];
        }
        printf("%d\n", len);
    }
    return 0;
}


其中对第一个代码,有个巨大的优化,这个复杂度为n*logn

首先

len = 1,dp[1] = a[1],然后对a[i]:若a[i]>dp[len],那么len++,dp[len] = a[i];
否则

我们要从d[1]到dp[len-1]中找到一个j,满足dp[j-1]<a[i]<d[j]

根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 dp[j] = a[i];
最终

答案就是len
利用dp的单调性,在查找j的时候可以二分查找,从而时间复杂度为n*logn


再看一个用stl写的

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include<vector>
#include<queue>
#include<algorithm>

using namespace std;
typedef long long LL;

const int maxn=500009;
const int INF=0x3f3f3f3f;

int n;
int a[maxn];
int dp[maxn];

int main()
{
    int T;
    scanf("%d", &T);

    while(T--)
    {
        scanf("%d", &n);

        for(int i=1; i<=n; i++)
            scanf("%d", &a[i]);

        dp[0]=0;
        int len=0;

        for(int i=1; i<=n; i++)
        {
            if(a[i]>dp[len])
            {
                dp[++len]=a[i];
                continue;
            }

            int t=upper_bound(dp, dp+len, a[i])-s;
            dp[t]=a[i];
        }

        printf("%d\n", len);
    }
    return 0;
}

函数具体,看大牛的博客吧!

http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html




好吧!没有,最近在学习树状数组,忽然我……………………………………


在网上看到了,一个用来树状数组写的,还不错就打了一遍!

不解释,想看就看,不看也无关!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005
#define MAX 0x3f3f3f3f

using namespace std;

struct point
{
    int num, x;
}a[N];

int dp[N], n;

bool comp(point  a, point b)
{
    if(a.num == b.num)
        return a.x < b.x;
    return a.num < b.num;
}

int lowbit(int x)
{
    return x & (-x);
}

int find(int x)
{
    int ret = -MAX;
    while(x)
    {
        ret = max(ret, dp[x]);
        x -= lowbit(x);
    }
    return ret;
}

void change(int x ,int y)
{
    while(x <= n)
    {
        dp[x] = max(dp[x], y);
        x += lowbit(x);
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(dp, 0, sizeof(dp));
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i].num);
            a[i].x = i;
        }

        sort(a + 1, a + n + 1, comp);

        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int mmax = find(a[i].x);
            change(a[i].x, ++mmax);
            ans = max(ans, mmax);
        }
        printf("%d\n", ans);
    }
    return 0;
}

最后,推荐一个博客吧!讲了三种解决方法(写的很好,但是感觉没必要)

http://blog.csdn.net/george__yu/article/details/75896330#reply



 



猜你喜欢

转载自blog.csdn.net/newproblems/article/details/77159149