Paintball

15 篇文章 0 订阅
4 篇文章 0 订阅

E - Paintball

 HDU - 3767 

题目大意:

给定:

设定 一个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 不要搞混淆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值