例题 6-22 战场(Paintball, UVA 11853)

原题链接:https://vjudge.net/problem/UVA-11853
分类:图
备注:对偶图,BFS

根据紫书的思路:
1、判断有无解,将敌人看作一个圆,从上边界开始遍历,把所有相连敌人范围遍历完后若发现能到底部,说明路被堵死。
2、求最北的入/出口,从上边界开始遍历,若有敌人占据的范围与x=0.00的边界有交点,取其中最南的值,出口同理,求与x=1000.00的最南交点。根据:若存在这样的交点说明在该点以及之上的点,进入后是被敌人包围的,无法通过。若没有这样的交点,则答案为1000.00。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int maxn = 1000 + 5;
int n;
double inAns, outAns;
struct node {
	double x, y, r, r2, top, bot, maxL, maxR;
	int pos;
	bool operator <(const node& a) {
		return top > a.top;
	}
}p[maxn];
double disTwo(double x1, double y1, double x2, double y2) {
	return (pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
void update(int pos) {
	if (p[pos].maxL == 0.00)
		inAns = min(inAns, p[pos].y - sqrt(p[pos].r2 - pow(p[pos].x, 2)));
	if (p[pos].maxR == 1000.00)
		outAns = min(outAns, p[pos].y - sqrt(p[pos].r2 - pow(1000.00 - p[pos].x, 2)));
}
bool canSolve() {
	int vis[maxn] = { 0 };
	queue<node>Q;
	for (int i = 0; i < n; i++) {
		if (p[i].top == 1000) {
			p[i].pos = i;
			Q.push(p[i]);
			vis[i] = 1;
			update(i);
		}
		else break;
	}
	while (!Q.empty()) {
		node u = Q.front(); Q.pop();
		if (u.bot == 0)return false;
		double x1 = u.x, y1 = u.y;
		for (int i = u.pos + 1; i < n; i++) {
			if (vis[i])continue;
			double x2 = p[i].x, y2 = p[i].y;
			if (disTwo(x1, y1, x2, y2) <= pow(u.r + p[i].r, 2)) {
				p[i].pos = i;
				Q.push(p[i]);
				vis[i] = 1;
				update(i);
			}
		}
	}
	return true;
}
int main(void) {
	while (~scanf("%d", &n)) {
		inAns = outAns = 1000.00;
		for (int i = 0; i < n; i++) {
			scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].r);
			p[i].r2 = pow(p[i].r, 2);
			p[i].top = min(1000.00, p[i].y + p[i].r);
			p[i].bot = max(0.00, p[i].y - p[i].r);
			p[i].maxL = max(0.00, p[i].x - p[i].r);
			p[i].maxR = min(1000.00, p[i].x + p[i].r);
		}
		sort(p, p + n);
		if (!canSolve()) {
			printf("IMPOSSIBLE\n");
			continue;
		}
		printf("0.00 %.2f 1000.00 %.2f\n", inAns, outAns);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JILIN.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值