hdu 4268 Alice and Bob

Alice and Bob

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1253    Accepted Submission(s): 478

Problem Description
Alice and Bob's game never ends. Today, they introduce a new game. In this game, both of them have N different rectangular cards respectively. Alice wants to use his cards to cover Bob's. The card A can cover the card B if the height of A is not smaller than B and the width of A is not smaller than B. As the best programmer, you are asked to compute the maximal number of Bob's cards that Alice can cover.
Please pay attention that each card can be used only once and the cards cannot be rotated.
 
 
Input
The first line of the input is a number T (T <= 40) which means the number of test cases.
For each case, the first line is a number N which means the number of cards that Alice and Bob have respectively. Each of the following N (N <= 100,000) lines contains two integers h (h <= 1,000,000,000) and w (w <= 1,000,000,000) which means the height and width of Alice's card, then the following N lines means that of Bob's.
 
 
Output
For each test case, output an answer using one line which contains just one number.
 
 
Sample Input
2 2 1 2 3 4 2 3 4 5 3 2 3 5 7 6 8 4 1 2 5 3 4
 
 
Sample Output
1 2
 
 
Source
 
 
Recommend
liuyiding
 
这个题网络赛当天没有看,今天看了看,直觉告诉我stl可以搞(其实人家解题报告也这么写的)。今天写出好几种方法,结果有ac,tle,wa。下面我把我的思考过程写一下。
先来一个wa代码:
View Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>

using namespace std;

int n;

struct Card
{
    int person;
    int height;
    int width;
    bool operator < (const Card &t) const
    {
        if(height!=t.height) return height<t.height;
        if(width!=t.width) return width<t.width;
        return person>t.person;
    }
};

std::set<Card>v;
std::priority_queue<Card>s;

void data_in()
{
    scanf("%d",&n);
    Card card;
    v.clear();
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<n;j++)
        {
            int tmp1,tmp2;
            scanf("%d %d",&tmp1,&tmp2);
            card.person=i,card.height=tmp1,card.width=tmp2;
            v.insert(card);
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        data_in();
        int cnt=0;
        std::set<Card>::iterator it;
        while(!s.empty())
            s.pop();
        for(it=v.begin();it!=v.end();it++)
        {
//            cout<<(*it).person<<" "<<(*it).height<<" "<<(*it).width<<endl;
            if((*it).person==0)
            {
                if(!s.empty())
                {
                    cnt++;
                    s.pop();
                }
            }
            else s.push((*it));

//            cout<<cnt<<endl;
        }
        printf("%d\n",cnt);
    }
    return 0;
}

这个代码在杭电oj用c++提交跑了1500ms整。当时我以为已经接近ac了,后来就一直调试,但是结局总是不尽如人意。我先声明,之前我并没有看解题报告。信不信由你,哈哈,娱乐一下嘛,毕竟这个题各种思路我想了一天。我先用set来保存了alice跟bob的卡片的高度和宽度,并重载<号。之后扫描set用一个优先队列来维护之前没有用到过的bob的卡片,如果遇到一个alice的卡片就对优先队列来处理,但是很可惜里面有一个地方没处理对。是因为后来学长给了我一组数据:

1

2

2 7

3 5

1 4

2 7

按照我的代码用是用alice的2 7 去coverbob的1 4,剩下就不能cover了,但这明显是错的。关键就是在这个地方优先队列的优先级出问题了。之后改过之后,发现会有多个bob的卡片可以被alice的某一张卡片所覆盖,但是这时又该如何抉择呢,发现还是不能解决问题,当然就引出了下面的代码,用到了stl的multiset,里面自带的upper_bound函数。

View Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <set>

using namespace std;

int n;

struct Card
{
    int person;
    int height;
    int width;
    bool operator < (const Card &t) const
    {
        if(height!=t.height) return height<t.height;
        if(width!=t.width) return width<t.width;
        return person>t.person;
    }
};

std::vector<Card>v;
std::multiset<int>s;

void data_in()
{
    scanf("%d",&n);
    Card card;
    v.clear();
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<n;j++)
        {
            int tmp1,tmp2;
            scanf("%d %d",&tmp1,&tmp2);
            card.person=i,card.height=tmp1,card.width=tmp2;
            v.push_back(card);
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        data_in();
        sort(v.begin(),v.end());
        int cnt=0;
        std::vector<Card>::iterator it;
        s.clear();
        for(it=v.begin();it!=v.end();it++)
        {
            if((*it).person==0)
            {
                if(it==v.begin()) continue;
                else
                {
                    if(!s.empty())
                    {
                        std::multiset<int>::iterator itt;
                        itt=s.upper_bound((*it).width);
                        if(itt!=s.begin())
                        {
                            itt--;
//                            printf("%d\n",(*itt));
//                            system("pause");
                            cnt++;
                            s.erase(itt);
                        }
                        else continue;
                    }
                    else continue;
                }
            }
            else
                s.insert((*it).width);
        }
        printf("%d\n",cnt);
    }
    return 0;
}

代码我就不过多解释了。仔细想一下很容易明白。之后我想到set内部是一棵自建的红黑树。我想那个upper_bound到底怎么运作的呢?当然是先想到的这个思路:遇到bob的卡片先插入,遇到alice的卡片就把数组里面的bob的卡片按照升序排列,然后二分这个数组寻找上界。下面就是这个思路的代码,但是是tle的:

View Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <set>
#define inf 0x7fffffff

using namespace std;

int n;

struct Card
{
    int person;
    int height;
    int width;
    bool operator < (const Card &t) const
    {
        if(height!=t.height) return height<t.height;
        if(width!=t.width) return width<t.width;
        return person>t.person;
    }
};

std::vector<Card>v;
std::multiset<int>s;

void data_in()
{
    scanf("%d",&n);
    Card card;
    v.clear();
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<n;j++)
        {
            int tmp1,tmp2;
            scanf("%d %d",&tmp1,&tmp2);
            card.person=i,card.height=tmp1,card.width=tmp2;
            v.push_back(card);
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        data_in();
        sort(v.begin(),v.end());
        int cnt=0;
        std::vector<Card>::iterator it;
        s.clear();
        int us[100000];
        int ustart = 1,l,r,mid;
        for(it=v.begin();it!=v.end();it++)
        {
            if((*it).person==0)
            {
                if(it==v.begin()) continue;
                else
                {
                    sort(us+1,us+ustart+1);
                    if(ustart)
                    {
                        l=1;
                        r=ustart;
                        while(l<r)
                        {
                            mid=(l+r)>>1;
                            if(us[mid]<=(*it).width)
                                l=mid+1;
                            else
                                r=mid;
                        }
                        if(mid&&us[mid]!=inf)
                        {
                            cnt++;
                            us[mid]=inf;
                        }

                    }
//                    if(!s.empty())
//                    {
//                        std::multiset<int>::iterator itt;
//                        itt=s.upper_bound((*it).width);
//                        if(itt!=s.begin())
//                        {
//                            itt--;
//                            cnt++;
//                            s.erase(itt);
//                        }
//                        else continue;
//                    }
//                    else continue;
                }
            }
            else
                //s.insert((*it).width);
                us[ustart++] = (*it).width;
        }
        printf("%d\n",cnt);
    }
    return 0;
}

肯定是sort超时了,没细想什么时间复杂度,拓展自己思路嘛。后来想怎么搞这个sort呢。我想到在插入的时候可以O(n)处理一下,就是由后往前扫,扫到一个比他小的,就把他插在其后面。这样在遇到alice的卡片之后就不会花费nlogn去排序了,但是插入之后涉及到数据的移动,这样一来估计连nlogn都比不上,呵呵,脑残了一下。之后学长说用什么拉链的方法,那个方法我现在也不知道,但是试着写了写,发现也蛮好写的,下面是这个思路的代码,但是是残的,不会有正确结果,估计也编译不过吧,问题出在了用到过的卡片我会把把的width弄成inf之后二分的时候遇到这些值处理不了了。所以这个思路就放弃了。但我还是把代码弄上来:

View Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <set>

#define inf 1<<17
#define iinf 0x7fffffff

using namespace std;

int n;

struct Card
{
    int person;
    int height;
    int width;
    bool operator < (const Card &t) const
    {
        if(height!=t.height) return height<t.height;
        if(width!=t.width) return width<t.width;
        return person>t.person;
    }
};

struct node
{
    node *next;
    int data;
    int count;
    node()
    {
        next=NULL;
        data=0;
        count=0;
    }
}us[100010];

std::vector<Card>v;
std::multiset<int>s;

void data_in()
{
    scanf("%d",&n);
    Card card;
    v.clear();
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<n;j++)
        {
            int tmp1,tmp2;
            scanf("%d %d",&tmp1,&tmp2);
            card.person=i,card.height=tmp1,card.width=tmp2;
            v.push_back(card);
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        data_in();
        sort(v.begin(),v.end());
        int cnt=0;
        std::vector<Card>::iterator it;
        s.clear();
        int ustart = 1,l,r,mid,mmid;
        for(it=v.begin();it!=v.end();it++)
        {
            cout<<(*it).height<<" "<<(*it).width<<" "<<(*it).person<<endl;
            if((*it).person==0)
            {
                if(it==v.begin()) continue;
                else
                {
//                    sort(us+1,us+ustart+1);
                    if(ustart)
                    {
                        l=1;
                        r=ustart;
                        while(l<r)
                        {
                            mid=(l+r)>>1;
                            if(us[mid].data<=(*it).width)
                                l=mid+1;
                            else
                                r=mid;
                        }
//                        cout<<mid<<" "<<us[mid].data<<endl;
                        if(mid&&us[mid].data!=inf)
                        {
//                            cout<<"yes"<<endl;
//                            cout<<us[mid].count<<endl;
                            if(us[mid].count==1)
                            {
                                us[mid].data=inf;
                                cnt++;
//                                cout<<"yes"<<endl;
                            }
                            else
                            {
                                l=1,r=us[mid].count;
                                while(l<r)
                                {
                                    mmid=(l+r)>>1;

                                    if(us[mid].next[mmid].data<=(*it).width)
                                        l=mmid+1;
                                    else r=mmid;
                                }
                                if(mmid&&us[mid].next[mmid].data!=inf)
                                {
                                    us[mid].next[mmid].data=inf;
                                    cnt++;
                                }

                            }
                        }
                    }
//                    if(!s.empty())
//                    {
//                        std::multiset<int>::iterator itt;
//                        itt=s.upper_bound((*it).width);
//                        if(itt!=s.begin())
//                        {
//                            itt--;
//                            cnt++;
//                            s.erase(itt);
//                        }
//                        else continue;
//                    }
//                    else continue;
                }
            }
            else
                //s.insert((*it).width);
//                us[ustart++] = (*it).width;
                {
                    if(ustart==1)
                    {
                        us[ustart].next=NULL;
                        us[ustart].count=1;
                        us[ustart++].data=(*it).width;
                    }
                    else
                    {
                        l=1,r=ustart;
                        while(l<r)
                        {
                            mid=(l+r)>>1;
                            if(us[mid].data<=(*it).width)
                                l=mid+1;
                            else
                                r=mid;
                        }
                        if(mid&&mid==ustart-1)
                        {
                            if(us[ustart].data==inf||us)
                            us[ustart].next=NULL;
                            us[ustart].count=1;
                            us[ustart++].data=(*it).width;
//                              cout<<"yes"<<endl;
                        }
                        else
                        {
//                                cout<<"yes"<<endl;
                            us[mid].next[us[mid].count++].data=(*it).width;
                        }
                    }
//                    cout<<ustart<<endl;
                }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

这个代码比较狗屎。就当给大家提供个思路。后来我想到了线段树的思想,建一棵树来搞,具体怎么搞,还不是特别明朗,当然堆这方面似乎也是可以想想的。

总之感觉今天过的还好吧。多想想总是好的。谢谢。欢迎大家转载,留言。

 

posted on 2012-10-11 19:59  Raining Days  阅读(217)  评论(0编辑  收藏  举报

导航