原题链接: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;
}