UVa 传说中的车(白书P11134_放棋子+set)

22 篇文章 0 订阅
16 篇文章 0 订阅
该博客介绍了如何解决一个棋盘放棋子的问题,要求棋子不能相互攻击,并且每个棋子只能在特定矩形区域内放置。通过将问题分解为x和y轴的独立处理,使用贪心算法按区间右端点从小到大排序,从左端点开始寻找未被占用的点来放置棋子。博主分享了用C++实现的解决方案,包括数据结构和算法细节,最终时间复杂度为O(n*log(n))。
摘要由CSDN通过智能技术生成
题意:
      给你一个n*n的棋盘,让你在棋盘上放n个棋子,要求是所有棋子不能相互攻击(同行或者同列就会攻击),并且每个棋子都有一个限制,那就是必须在给定的矩形r[i]里,输出每个棋子的位置,special Jude。


思路:
      看完后第一反应就是匈牙利(哎!惭愧啊。)结果想着怎么建图,想了一会呵呵了,果断想别的方法,其实这个题目设计到一个小思想非常好,那就是把整体分解,这个题目说的是什么?是每个棋子都限制了一个矩形范围,矩形范围又是什么?是不是就是xl<=x<=xr&&rl<=y<=yr,其实x和y我们可以分开考虑,可以分开的原因就是x和y之间没有限制因素,也不会相互影响,就像是中学时学的速度分解一样,这个就是这个题目的关键点,想到这个AC的可能性就很大了,分解后我们要处理的就是给你一些区间限制,然后在每个区间内都必须选择一个点放东西,最后要求同一个点不能放两个东西,也就是本题目的同一行或者一列不能放两个其子一样,然后就是贪心了,怎么贪心呢?我们可以把每个区间都按照右端点从小到大排序,然后我们从前往后贪心,右端点越小的“自由性”越小,所以要先处理,所以放在前面,对于每一断,我们就从这个段的做端点开始找,找第一个没被占用的点,占用上就行了,如果都找到右端点了还没找到可以用的点,那么就直接没解了,x和y都是这么处理的,找的时候我用的是set容器总的时间复杂度是O(n*log(n)),如果不想用set直接暴力找也应该不会超时,时间复杂度是O(n*n).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstdio>
using namespace std;
int ansx[5555],ansy[5555];

struct node
{
	int l,r,index;
} x[5555],y[5555];

bool cmp(node x,node y)
{
	if(x.r<y.r) return true;
	return false;
}

int main()
{
	int n,i,j;
	set<int>set1,set2;
	while(scanf("%d",&n)==1 && n) {
		set1.clear();
		set2.clear();
		for(i=1;i<=n;i++) {
			cin>>x[i].l>>y[i].l>>x[i].r>>y[i].r;
			x[i].index=y[i].index=i;
			set1.insert(i);
			set2.insert(i);
		}
		set2.insert(10000);
		set1.insert(10000);
		sort(x+1,x+1+n,cmp);
		sort(y+1,y+1+n,cmp);
		int mk=0;
		for(i=1;i<=n&&!mk;i++) {
			int temp=*set1.lower_bound(x[i].l);
			if(temp>x[i].r) mk=1;
			ansx[x[i].index]=temp;
			set1.erase(temp);
			
			temp=*set2.lower_bound(y[i].l);
			if(temp>y[i].r) mk=1;
			ansy[y[i].index]=temp;
			set2.erase(temp);
		}
		if(mk) printf("IMPOSSIBLE\n");
		else {
			for(i=1;i<=n;i++) printf("%d %d\n",ansx[i],ansy[i]);
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值