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;
}

 

posted @ 2015-02-11 10:30  zhyfzy  阅读(756)  评论(0编辑  收藏  举报