[ZOJ 3052] Unix Robots [模拟]

本文介绍了一个关于机器人追逐玩家并可能发生碰撞的游戏算法。机器人遵循特定路径向玩家靠近,当两个机器人相遇或碰到黑洞时会消失。文章提供了一个C++实现方案,通过枚举所有可能的碰撞来判断是否有机器人能成功达到玩家位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目背景就是Unix下的同名游戏..

每个机器人每秒钟向你移动,移动方式是,假设你为原点,则他会沿着一条斜率为±1的直线靠近你,直到它移动到了某个坐标轴上,然后就沿着坐标轴靠近你。每秒钟每个坐标的变化量都最多是1。

如果两个机器人撞在了一起,即出现在了同一个坐标中,那么他们就会消失并产生一个黑洞。题目开始也会有一些黑洞。如果机器人移动到了黑洞上,则机器人也会消失。黑洞一旦出现就永远不会消失。

问你呆在一个位置不动,已知机器人的初始位置,他们同时开始向你移动,问能否有机器人最终移动到你的坐标?

如果机器人在你所在的位置上碰撞,是不算的。认为他们能够移动到你的坐标。

暴力枚举所有机器人和所有机器人的碰撞时间,以及所有机器人和所有黑洞的碰撞时间。复杂度10^6。

#include <cstdio>
#include <set>
#include <utility>

using namespace std;

const int INF=~0u>>1;

inline int sgn(int x) {
	if (x>0) return 1;
	if (x<0) return -1;
	return 0;
}
inline int abs(int x) {
	return x>0?x:-x;
}
inline int max(int a,int b) {
	return a>b?a:b;
}
inline int min(int a,int b) {
	return a<b?a:b;
}

struct Bomb {
	set<pair<int,int> >::iterator a,b;
	bool isBRobot;
	int t,x,y;
	Bomb(int tt) {
		t=tt;
	}
	Bomb(set<pair<int,int> >::iterator aa,set<pair<int,int> >::iterator bb,bool br) {
		isBRobot=br;
		a=aa;b=bb;
		//calculate bomb time and location
		int ax=aa->first,ay=aa->second,bx=bb->first,by=bb->second;
		if (isBRobot) {
			if (ax==bx) {
				if (abs(ay)<abs(ax)&&abs(by)<abs(bx)) {
					t=max(abs(ay),abs(by));
					if (ax>0) x=ax-t;
					else x=ax+t;
					y=0;
				} else t=INF;
			} else if (ay==by) {
				if (abs(ay)>abs(ax)&&abs(by)>abs(bx)) {
					t=max(abs(ax),abs(bx));
					x=0;
					if (ay>0) y=ay-t;
					else y=ay+t;
				} else t=INF;
			} else t=INF;
		} else {
			int tmp=min(abs(ax),abs(ay)),tmpx,tmpy;
			if (ax>0) tmpx=ax-tmp;
			else tmpx=ax+tmp;
			if (ay>0) tmpy=ay-tmp;
			else tmpy=ay+tmp;
			if ((abs(bx-tmpx)==abs(by-tmpy)&&abs(bx-tmpx)<=abs(ax-tmpx)&&sgn(bx-tmpx)==sgn(ax-tmpx)&&sgn(by-tmpy)==sgn(ay-tmpy)) 
				||(abs(bx)<=abs(tmpx)&&abs(by)<=abs(tmpy)&&sgn(bx)==sgn(tmpx)&&sgn(by)==sgn(tmpy))) {
				t=max(abs(ax-bx),abs(ay-by));
			} else t=INF;
		}
		//printf("Constructor: (%d,%d) (%d,%d)%c %d\n",a->first,a->second,b->first,b->second,br?'R':'C',t);
	}
	friend bool operator <= (const Bomb &a,const Bomb &b) {
		return a.t<=b.t;
	}
};

set<pair<int,int> >robot;
set<pair<int,int> >hole;
int sx,sy,n,m;

int main() {
	int i;
	while (scanf("%d%d",&sx,&sy)!=EOF) {
		robot.clear();
		hole.clear();
		scanf("%d",&n);
		for (i=0;i<n;i++) {
			int x,y;
			scanf("%d%d",&x,&y);
			robot.insert(make_pair(x-sx,y-sy));
		}
		scanf("%d",&m);
		for (i=0;i<m;i++) {
			int x,y;
			scanf("%d%d",&x,&y);
			hole.insert(make_pair(x-sx,y-sy));
		}
		bool ans=false;
		Bomb lastminBomb=Bomb(0);
		while (!robot.empty()) {
			Bomb minBomb=Bomb(INF);
			/*
			printf("New Round: --lastBomb %d\n",lastminBomb.t);
			printf("Robot:\n");
			for (set<pair<int,int> >::iterator it=robot.begin();it!=robot.end();it++) {
				printf(" (%d,%d)\n",it->first,it->second);
			}
			printf("Hole\n");
			for (set<pair<int,int> >::iterator it=hole.begin();it!=hole.end();it++) {
				printf(" (%d,%d)\n",it->first,it->second);
			}
			*/
			for (set<pair<int,int> >::iterator it1=robot.begin();it1!=robot.end();it1++) {
				set<pair<int,int> >::iterator it2=it1;
				it2++;
				while (it2!=robot.end()) {
					Bomb tmp=Bomb(it1,it2,true);
					if (lastminBomb<=tmp&&tmp<=minBomb) minBomb=tmp;
					it2++;
				}
			}
			for (set<pair<int,int> >::iterator it1=robot.begin();it1!=robot.end();it1++) {
				for (set<pair<int,int> >::iterator it2=hole.begin();it2!=hole.end();it2++) {
					Bomb tmp=Bomb(it1,it2,false);
					if (lastminBomb<=tmp&&tmp<=minBomb) minBomb=tmp;
				}
			}
			//printf("(%d,%d) (%d,%d) %d\n",minBomb.a->first,minBomb.a->second,minBomb.b->first,minBomb.b->second,minBomb.t);
			if (minBomb.t!=INF) {
				if (minBomb.isBRobot) {
					robot.erase(minBomb.a);
					robot.erase(minBomb.b);
					hole.insert(make_pair(minBomb.x,minBomb.y));
				} else {
					robot.erase(minBomb.a);
				}
			} else {
				ans=true;
				break;
			}
			lastminBomb=minBomb;
		}
		if (ans) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值