SPOJ 3943 - Nested Dolls 最长不下降子序列LIS(二分写法)

现在n(<=20000)个俄罗斯套娃,每个都有宽度wi和高度hi(均小于10000),要求w1<w2并且h1<h2的时候才可以合并,问最少能剩几个。

 

【LIS】乍一看跟【这题】类似,但是仔细看是有区别的,其实就相当于上一题多次求LIS,每次求完LIS后把得到的序列删去,然后重新求LIS,最后输出求LIS的次数,我一开始这样写,果然就TLE了。还是要另辟蹊径。

 

首先用贪心思想,先按照wi从大到小排序,wi相等的情况下hi从小到大,然后求最长不下降子序列(注意可以等于)。输出其长度即可。

 

想想为什么,如果有i和j这两个点满足wi>wj,hi>hj,显然是满足条件的,直接合并即可(所求序列长度不变),但是如果wi>wj,hi<=hj不可合并,那么序列长度就要增加。

如果wi==wj,那么无论hi与hj的关系如何都不可以合并,为了方便求最长不下降序列,可以假设hi<=hj,这样序列长度也会增加。因此wi相等的情况下hi要从小到大排序。

 

还有一个问题是LIS中二分查找的写法问题,我是卡在了这里,在网上看了看别人的代码后,把lower_bound改成了upper_bound竟然AC了!

 

lower_bound是返回序列中大于等于key值的第一个数

upper_bound是返回序列中严格大于key值的第一个数

 

显然最长上升子序列是严格递增的,因此每次更新后都不可以出现两个数相同的情况,因此使用lower_bound(比如1,2,3,4,新输入的数是3,使用lower_bound返回第三个数,即把3改成3,如果使用upper_bound返回第四个数,把4改成3,则会出现两个3,不符合条件)。而最长不下降子序列存在多个数相同的情况,因此使用upper_bound,这里解释同上。

 

#include<cstdio>

#include<cstring>

#include<cmath>

#include<iostream>

#include<algorithm>

#include<set>

#include<map>

#include<stack>

#include<vector>

#include<queue>

#include<string>

#include<sstream>

#define eps 1e-9

#define ALL(x) x.begin(),x.end()

#define INS(x) inserter(x,x.begin())

#define FOR(i,j,k) for(int i=j;i<=k;i++)

#define MAXN 20005

#define MAXM 40005

#define INF 0x3fffffff

using namespace std;

typedef long long LL;

int i,j,k,n,m,x,y,T,ans,big,cas,num,len;

bool flag;



struct node

{

    int s,b,i;

}p[MAXN];



int dp[MAXN];



bool cmp(node x,node y)

{

    if (x.s==y.s) return x.b<y.b;

    return x.s>y.s;

}



int main()

{

    scanf("%d",&T);

    while (T--)

    {

        scanf("%d",&n);

        

        for (i=1;i<=n;i++)

        {

            scanf("%d%d",&p[i].s,&p[i].b);

            p[i].i=i;

        }

        sort(p+1,p+1+n,cmp);

    

        num=0;

        for (i=1;i<=n;i++)//求最长不下降子序列

        {

            if (p[i].b>=dp[num])//与最长上升子序列求法不同的是这里改成大于等于

            {

                dp[++num]=p[i].b;

            }else

            {

                k=upper_bound(dp+1,dp+1+num,p[i].b)-dp; //与最长上升子序列求法不同的是这里改成upperbound

                

                dp[k]=p[i].b;

            }

        }

        

        printf("%d\n",num);

    }

    return 0;

}

 

你可能感兴趣的:(poj)