11853 - Paintball

You are playingpaintball on a 1000x1000 square field. A number of your opponents are on thefield hiding behind trees at various positions. Each opponent can fire apaintball a certain distance in any direction. Can you cross the field withoutbeing hit by a paintball?

Assume that thesouthwest corner of the field is at (0,0) and the northwest corner at (0,1000).

InputSpecification

The input containsseveral scenario. Each scenario consists of a line containing n <= 1000, thenumber of opponents. A line follows for each opponent, containing three realnumbers: the (x,y) location of the opponent and its firing range. The opponentcan hit you with a paintball if you ever pass within his firing range.

You must enter thefield somewhere between the southwest and northwest corner and must leavesomewhere between the southeast and northeast corners.

OutputSpecification

For each scenario,if you can complete the trip, output four real numbers with two digits afterthe decimal place, the coordinates at which you may enter and leave the field,separated by spaces. If you can enter and leave at several places, give themost northerly. If there is no such pair of positions, print the line: 
IMPOSSIBLE

Sample Input

3

500 500 499

0 0 999

1000 1000 200

Output forSample Input

0.00 1000.001000.00 800.00

代码:

#include<iostream>

#include<cmath>

#include<cstring>

#include<iomanip>

#include<algorithm>

using namespacestd;

 

const int maxn =1000 + 5;

const double W =1000.00;

 

int n, vis[maxn];

double x[maxn],y[maxn], r[maxn], Left, Right;

bool ok;

 

bool intersect(intc1, int c2)

{

    return sqrt((x[c1]-x[c2])*(x[c1]-x[c2]) +(y[c1]-y[c2])*(y[c1]-y[c2])) < r[c1] + r[c2];

}

 

voidcheck_circle(int u)

/*

注意该函数的前提是:下标为u的圆最上部超过了场地的上边界或者

下标为u的圆与最上部超过了场地上边界的圆相交

*/

{

    if(x[u] - r[u] < 0)

    {

        Left = min(Left, y[u] - sqrt(r[u]*r[u]- x[u]*x[u]));

    }

    if(x[u] + r[u] > W)

    {

        Right = min(Right, y[u] -sqrt(r[u]*r[u] - (W-x[u])*(W-x[u])));

    }

}

 

bool dfs(int u)//u是圆形的输入编号,能达到底部则返回true

{

    if(vis[u])//如果已经访问过,直接返回

    {

        return false;

    }

    vis[u] = 1;//标记已访问

    if(y[u] - r[u] <= 0)//若该圆上下贯通,则无法通过场地

    {

        return true;

    }

    for(int v = 0; v < n; v++)//遍历其余的所有圆形

    {

        if(intersect(u, v) && dfs(v))

//若存在其他的圆形与该圆形相交,不包括相切,则对另一个圆深搜

        {

            return true;//多圆相连,上下贯通

        }

    }

    check_circle(u);//目标线路可能存在,更新最北的位置

    return false;

}

 

int main()

{

    while(cin>>n)

    {

        ok = true;

        Left = Right = W;

        memset(vis, 0, sizeof(vis));//每组数据的访问标记都要清空

        for(int i = 0; i < n; i++)

        {

           cin>>x[i]>>y[i]>>r[i];

        }

        for(int i = 0; i < n; i++)//遍历每一个圆形

        {

            if(y[i] + r[i] >= W&&dfs(i))

/*

充分利用‘&&’短路的特性,因为题目要求出最北边(最上面的)的坐标,

因此,如果该圆形没有越过最上边界的可能,那么该圆形不可能阻挡目标线路

即没有必要再对该圆形进行深搜

*/

            {

                ok = false; // 从上往下dfs

                break;

            }

        }

        if(ok)

        {

           cout<<"0.00"<<fixed<<setprecision(2)<<""<<Left<<" "<< W<<""<<Right<<endl;

        }

        else

        {

           cout<<"IMPOSSIBLE\n";

        }

    }

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值