HDU OJ 1677 Nested Dolls【二分,LIS】

原题连接:http://acm.hdu.edu.cn/showproblem.php?pid=1677

题意:每组测试数据给n个硬币,现在给你这n个硬币的长和高,若一硬币的长和高都小于另一个硬币,则这来个硬币可嵌套为一个硬币。。求最后剩余的最小硬币数。

思路:首先肯定能想到的是 贪心,不停遍历,不停更新。。复杂度 n*n (超时!!),然后又想到和以前做的题类似,有想到 二分图匹配之最小路径覆盖。。这个题数据20000个点,铁定超时。。看了xiaod的博客,看到一种牛叉的算法。。首先 按照 长 对硬币排序(由大到小),然后对于所有硬币的高组成的一个序列,求最长单调递增子序列的个数,这就是问题的解!仔细想一下,列出求的单调递增序列对应的硬币,发现他们任意两两都是不能嵌套的。然后其余的硬币都可以嵌套进入这些硬币中!这个想法太神奇了……对于求最长单调递增子序列,要是动态规划复杂度n*n,还是要超时的。这里再利用二分查找,复杂度O(n*logn),就能AC了……

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int Ans[22000],sum;
struct Doll
{
    int x;
    int y;
    bool operator<(const Doll&t)const
    {
        return x>t.x||x==t.x&&y<t.y;
    }
}d[22000];
bool cmp(Doll t1,Doll t2)
{
    if(t1.x!=t2.x)
        return t1.x>t2.x;
    else
        return t1.y<t2.y;
}
void Binary(int dd)
{
    int x=0,y=sum;
    while(x<y)
    {
        int mid = (x+y)/2;
        if(Ans[mid]>dd)
            y=mid;
        else
            x=mid+1;
    }
    Ans[y]=dd;
}
int main()
{
    int i,j,n,ncase;
    cin>>ncase;
    while(ncase--)
    {
        cin>>n;
        for(i=0;i<n;i++)
            scanf("%d%d",&d[i].x,&d[i].y);
        sort(d,d+n);
        sum=0;
        Ans[sum++]=d[0].y;
        for(i=1;i<n;i++)
        {
            if(d[i].y>=Ans[sum-1])
                Ans[sum++]=d[i].y;
            else
                Binary(d[i].y);
        }
        cout<<sum<<endl;
    }
    return 0;
}


你可能感兴趣的:(算法,语言)