HDU4268 2012ACM长春赛区网络赛 Alice and Bob

题目: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;
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值