E - Paintball
题目大意:
给定:
设定 一个1000 *1000 大小的区域范围
对应的坐标左下角(0,0) 右上角(1000,1000)
并给定一个数 N ,给出 N 组数据,每组数据 分别为 x坐标 y坐标 和对应的攻击范围 R 这里描述的是一个圆的坐标和对应的范围区域大小
要求:
要求你从区域的最左边 通往区域的最右边
并且不能碰到对应的区域范围, 如果不能通过,则返回-1
能通过 则返回左边进入的坐标和右边进入的坐标,并且 坐标尽可能偏北的坐标。
思路:
对每一个圆 进行遍历,查看是否超出了上边界,如果超出上边界,那么判断是否有黏连的圆,如果黏连的圆中有超出下边界的,那么就可以知道从左是无法同过最右边的。并且对每个超出左边界和右边界的圆,对其判断是否需要更新左右两边的最大入口左边和出口坐标(0,left)(1000,right)
代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 1005;
const double Wide = 1000.0;
double xx[MAXN],yy[MAXN],rr[MAXN];
int N;
bool vis[MAXN];
double Left,Right;
bool intersection(int u,int v){
return sqrt((xx[u]-xx[v])*(xx[u]-xx[v]) + (yy[u]-yy[v])*(yy[u]-yy[v]))<= rr[u]+rr[v];
}
void check_circle(int a){
if(xx[a]- rr[a] <= 0 ) Left = min(Left , yy[a] - sqrt(rr[a]*rr[a] - xx[a]*xx[a]));
if(xx[a]+ rr[a] >= Wide) Right = min(Right, yy[a] - sqrt(rr[a]*rr[a] - (Wide - xx[a])*(Wide - xx[a])));
}
bool dfs(int u){
if(vis[u]) return false;
vis[u] = true;
if(yy[u] - rr[u] <= 0) return true;
for(int i=1;i<=N;i++){
if(u == i || vis[i]) continue;
if(intersection(u,i) && dfs(i)) return true;
}
check_circle(u);
return false;
}
int main(){
while(~scanf("%d",&N)){
memset(vis,false,sizeof(vis));
Left = Right = Wide;
for(int i=1;i<=N;i++){
scanf("%lf%lf%lf",&xx[i],&yy[i],&rr[i]);
}
bool ok = true;
for(int i=1;i<=N;i++){
if(!vis[i] && yy[i] + rr[i] >= Wide && dfs(i)){
ok = false;
break;
}
}
if(ok) printf("%.2f %.2f %.2f %.2f\n",0.000,Left,Wide,Right);
else printf("IMPOSSIBLE\n");
}
return 0;
}
注意调用的顶点i 不要搞混淆