题目:HDU4268(贪心)
题意是Alice和Bob都有N张卡片,卡片各有尺寸,Alice拿自己的卡片分别去盖Bob的,给出每张卡片的尺寸,问最多可以盖住多少张。
先说一下我错误的解题方法,主要思想就是拿最大的去盖最大的。分别对Alice和Bob的卡片在两个set中进行排序(排序是自动的),
按卡片的h降序排,h相同时按w的降序排。然后以Bob的set做循环,取Alice的set首端的卡片去盖,能盖住则删去,代码如下:
#include <iostream> //#include <fstream> #include <set> #define FOR(a,b) for(int i = (a);i < (b);i ++) using namespace std; class Card { public: int h,w; bool operator<(const Card& c) const //插入set时自动排序,要自定义"<"操作符 { if( h == c.h) return w < c.w; return h < c.h; } bool CanCover(const Card& c) const { return (h >= c.h && w >= c.w); } }; int main() { //ifstream cin("in.txt"); multiset<Card> Alice,Bob; multiset<Card>::iterator ap,bp; Card c; int t,n,ans; cin>>t; while (t --) { Alice.clear(); Bob.clear(); ans = 0; cin>>n; FOR(0,n) { cin>>c.h>>c.w; Alice.insert(c); } FOR(0,n) { cin>>c.h>>c.w; Bob.insert(c); } ap = Alice.begin(); while (ap != Alice.end()) { bp = Bob.begin(); if(ap->CanCover(*bp)) { Bob.erase(bp); ans ++; } ap ++; } cout<<ans<<endl; } }
我拿着这个代码提交了好几次都不对,然后就去参考了牛人的博客,看了半天才发现自己陷入了思维定势,正确思维应该是,对于Bob的每张卡片,把Alice的满足高度大于这张卡片的所有卡片组成一个集合(set),从集合中找w最接近的卡片,找到则从集合中删去。
正确的代码如下:
#include <iostream> //#include <fstream> #include <set> #include <algorithm> #define FOR(a,b) for(int i = (a); i < (b); i ++) using namespace std; const int maxnum = 100005; struct Card { int h,w; bool operator<(Card& c) { return (h < c.h); } }; Card Alice[maxnum],Bob[maxnum]; int main() { //ifstream cin("in.txt"); multiset<int> mi; multiset<int>::iterator mit; int t,n,ans; cin>>t; while (t --) { cin>>n; memset(Alice,0,sizeof(Card)*n); memset(Bob,0,sizeof(Card)*n); mi.clear(); ans = 0; FOR(0,n) { cin>>Alice[i].h>>Alice[i].w; } FOR(0,n) { cin>>Bob[i].h>>Bob[i].w; } sort(Alice,Alice+n); sort(Bob,Bob+n); int p = 0; FOR(0,n) { while (p < n && Bob[p].h <= Alice[i].h) { mi.insert(Bob[p].w); p ++; } if(mi.size()) { mit = mi.lower_bound(Alice[i].w); if(mit == mi.end()) mit --; if(mit != mi.begin() && Alice[i].w < *mit) mit --; if(Alice[i].w >= *mit) { mi.erase(mit); ans ++; } } } cout<<ans<<endl; } }