时间限制:10.000秒(JAVA)/5.000秒(其他语言)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4268
组队赛秃头了……
当时一晚上死磕的就是这道题,结果到最后也没做出来。看了别人的代码之后有种恍然大悟的感觉,看来思路还是不够开阔啊……
一说“Alice and Bob”八成就是博弈了。题意倒是挺简单,就是输入Alice和Bob的n个矩形的高和宽,当一个矩形高和宽均大于等于另一个矩形的时候,那么这个矩形可盖住该矩形,问Alice最多可以盖住Bob多少个矩形。
可以说是个贪心吧,每次用Alice的一个矩形盖住它能够盖住的最大矩形。自然而然地想到在输入之后要对两个人的矩形进行排序,然后在排好序的结构内二分查找,这是一开始的想法。然而,这题比较麻烦的地方是,排序是先按高再按宽排序或者反过来,然而判断是否盖住需要的是高和宽均大于另一个矩形。比赛的时候就是因为这个问题没有处理好,一开始答案错误,后来超时……
正解则用到了multiset——多重集合容器,天生有序并且允许元素重复。开始将Alice和Bob的矩形全部排好序,排序方式是先高后宽。然后Alice的矩形从小到大挑,每次选一个后将Bob的矩形中高小于等于该矩形的矩形的宽全部放进集合(注意:不是从头开始放,而是从上一次放过的位置继续,具体可见代码),然后再用upper_bound查找(upper_bound找到的是大于传入参数的第一个元素的位置),根据返回的位置判断是否有能够盖住的矩形,如果有,则将该宽的数据删除。因为下一次将Bob矩形放入集合的时候是从上一次放入矩形的最后一个位置向后继续放,所以每个矩形只会存入一次,不会造成重复和时间的浪费。
#include
#include
#include
#include
using namespace std;
struct rect {
int h, w;
bool operator < (const rect &r) const {
if(h != r.h) return h < r.h;
else return w < r.w;
}
};
const int maxn = 100010;
rect a[maxn], b[maxn];
multiset
ss; int main() { // freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while(T--) { int N; scanf("%d", &N); for(int i = 0; i != N; ++i) scanf("%d%d", &a[i].h, &a[i].w); for(int i = 0; i != N; ++i) scanf("%d%d", &b[i].h, &b[i].w); sort(a, a + N); sort(b, b + N); ss.clear(); int sum = 0; for(int i = 0, j = 0; i != N; ++i) { for( ; j < N && a[i].h >= b[j].h; ++j) ss.insert(b[j].w); multiset
::iterator p = ss.upper_bound(a[i].w); if(p != ss.begin()) { sum += 1; ss.erase(--p); } } printf("%d\n", sum); } }