Alice and Bob
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1836 Accepted Submission(s): 662
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
本题实则是个贪心问题,我们自己要找到贪心策略—
若Alice的方块能覆盖一个Bob的,则在h满足的情况下尽可能地选择w大的(前提是Alice大的h必须是有序的)。因为当前若Alice的h为之前取过的最大的且是之后去过的最小的,若其h能覆盖一些Bob的方块,则之后的H(H>=h)都能覆盖这些,只是若别覆盖的方块的w取得不好的话,可能导致后面的h能满足但w不能满足,从而出错。
可以通过枚举法直接选取,但时间复杂度最多可能会达O(n*n*n),在N <= 100,000的情况下肯定会超时,必须通过有效的方法降低时间复杂度。
1.不加优化的超时代吗,时间复杂度为O(N*N)
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int MAX=100000*2+100;
struct rectangular
{
int h,w,bel;
}Rect[MAX];
multiset<int>MulSet;
multiset<int>::iterator iter;
bool cmp1(rectangular a,rectangular b)
{
if(a.h!=b.h)
return a.h<b.h;
else if(a.w!=b.w)
return a.w<b.w;
else
return a.bel>b.bel;//保证来一个Alice的方块后它能覆盖的Bob的方块已出现
}
int main()
{
int cas,i,n,ans,j,Max,ind;
cin>>cas;
while(cas--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&Rect[i].h,&Rect[i].w);
Rect[i].bel=1;
}
for(i=n;i<2*n;i++)
{
scanf("%d%d",&Rect[i].h,&Rect[i].w);
Rect[i].bel=2;
}
ans=0;
sort(Rect,Rect+2*n,cmp1);
for(i=0;i<2*n;i++)
{
if(Rect[i].bel==1)
{
Max=-1;
for(j=i-1;j>=0;j--)
{
if(Rect[j].bel==2)
{
if(Rect[j].w<=Rect[i].w&&
Rect[j].w>Max)
{
Max=Rect[j].w;
ind=j;
}
}
}
if(Max!=-1)
{
ans++;
Rect[ind].bel=-1;
}
}
}
printf("%d\n",ans);
}
return 0;
}
2.使用STL的升级代码,时间复杂度降为O(N*logN),有效降低了时间复杂度,提高程序的效率。
set与multiset函数功能差不多,只是set和multiset会根据特定的排序准则,自动将元素进行排序。不同的是后者允许元素重复而前者不允许。
iterator lower_bound( const key_type &key ): 返回一个 迭代器,指向
键值>= key的第一个元素。
iterator upper_bound( const key_type &key ):返回一个迭代器,指向
键值> key的第一个元素。
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int MAX=100000*2+100;
struct rectangular
{
int h,w,bel;
}Rect[MAX];
multiset<int>MulSet;
multiset<int>::iterator iter;
bool cmp1(rectangular a,rectangular b)
{
if(a.h!=b.h)
return a.h<b.h;
else if(a.w!=b.w)
return a.w<b.w;
else
return a.bel>b.bel;//保证来一个Alice的方块后它能覆盖的Bob的方块已出现
}
int main()
{
int cas,i,n,ans;
cin>>cas;
while(cas--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&Rect[i].h,&Rect[i].w);
Rect[i].bel=1;
}
for(i=n;i<2*n;i++)
{
scanf("%d%d",&Rect[i].h,&Rect[i].w);
Rect[i].bel=2;
}
MulSet.clear();
ans=0;
sort(Rect,Rect+2*n,cmp1);
for(i=0;i<2*n;i++)
{
if(Rect[i].bel==1)
{
if(!MulSet.empty())
{
iter=MulSet.begin();
if(Rect[i].w>=(*iter))
{
ans++;
iter=MulSet.upper_bound(Rect[i].w);//关键字大于Rect[i].w的第一个
iter--;//保证删除小于等于Rect[i].w的MulSet中最大的元素
MulSet.erase(iter);
}
}
}
else
{
MulSet.insert(Rect[i].w);
}
}
printf("%d\n",ans);
}
return 0;
}