Paintball UVA - 11853 图的连通性,创新型题目

题目链接

题目大意:

You are playing paintball on a 1000×1000 square field. A number of your opponents are on the field hiding behind trees at various positions. Each opponent can fire a paintball a certain distance in any direction. Can you cross the field without being hit by a paintball? Assume that the southwest corner of the field is at (0,0) and the northwest corner at (0,1000).

你在一个1000×1000平方的场上玩彩弹。 你的许多对手都在躲在不同位置的树后面。 每个对手可以在任何方向上将彩弹射入一定距离。 你可以穿过这个领域而不被彩弹击中吗? 假设该字段的西南角位于(0,0),西北角位于(0,1000)。

分析:

    本题初看起来比较麻烦,不妨把它简化-下:先判断是否有解,再考虑如何求出最靠北的位置。首先,可以把每个敌人抽象成一个圆, 圆心就是他所在位置,半径是攻击范围,则本题变成了:正方形内有n个圆形障碍物,是否能从左边界走到右边界?

    下一步需要点创造性思维:把正方形战场看成一个湖, 障碍物看成踏脚石,如果可以从上边界“走”到下边界,沿途经过的障碍物就会把湖隔成左右两半,相互无法到达,即本题无解;另-方面,如果从上边界走不到下边界,虽然仍然可能会出现某些封闭区域,但一定可以从左边界的某个地方到达右边界的某个地方。

    这样,解的存在性只需一次DFS或BFS判连通即可。方法如下:  从上边界开始遍历,沿道检查与边界相交的圆。这些圆和左边界的交点中最靠南边的一个就是所来的最北进入位置,和右边界的最南交点就是所求的最北离开位置。

抄自:紫书

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
struct Node {
    double x,y,range;
}node[maxn];
bool vis[maxn];
int n;
double l, r;
bool is_con(int u, int v) {
    return (node[u].range+node[v].range)>=sqrt((node[u].x-node[v].x)*(node[u].x-node[v].x)+(node[u].y-node[v].y)*(node[u].y-node[v].y));
}

bool dfs(int u) {
    vis[u] = true;
    if(node[u].y-node[u].range<=0) return true;//超出下界
    for(int v = 0; v < n; v++) 
        if(!vis[v] && is_con(u,v) && dfs(v)) return true;
    if(node[u].x-node[u].range<=0) //超出左界
        l = min(l, node[u].y-sqrt(node[u].range*node[u].range-node[u].x*node[u].x));
    if(node[u].x+node[u].range>=maxn)
        r = min(r, node[u].y-sqrt(node[u].range*node[u].range-(1000-node[u].x)*(1000-node[u].x)));
    return false;
}

int main() {
    freopen("i.txt","r",stdin);
    freopen("o.txt","w",stdout);
    while(cin >> n) {
        l = r = (double)maxn;
        bool flag = true;
        memset(node,0,sizeof(node));
        memset(vis,false,sizeof(vis));
        for(int i = 0; i < n; i++) 
            cin >> node[i].x >> node[i].y >> node[i].range;
        for(int i = 0; i < n; i++) {
             if(!vis[i] && node[i].y+node[i].range>=maxn && dfs(i)) { //要超出上界
                flag = false;
                break;
            }
        }
        if(!flag) cout << "IMPOSSIBLE" << endl;
        else printf("0.00 %.2f %.2f %.2f\n",l,(double)maxn,r);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值