• [POJ 2588]--Snakes(并查集)


    题目链接:http://poj.org/problem?id=2588

    Snakes

    Time Limit: 1000MS   Memory Limit: 65536K
     

     

    Description

    Buffalo Bill wishes to cross a 1000x1000 square field. A number of snakes are on the field at various positions, and each snake can strike a particular distance in any direction. Can Bill make the trip without being bitten?

    Input

    Assume that the southwest corner of the field is at (0,0) and the northwest corner at (0,1000). The input consists of a line containing n <= 1000, the number of snakes. A line follows for each snake, containing three real numbers: the (x,y) location of the snake and its strike distance. The snake will bite anything that passes closer than this distance from its location.

    Output

    Bill must enter the field somewhere between the southwest and northwest corner and must leave somewhere between the southeast and northeast corners. 

    If Bill can complete the trip, give coordinates at which he may enter and leave the field. If Bill may enter and leave at several places, give the most northerly. If there is no such pair of positions, print "Bill will be bitten." 

    Sample Input

    3
    500 500 499
    0 0 999
    1000 1000 200
    

    Sample Output

    Bill enters at (0.00, 1000.00) and leaves at (1000.00, 800.00).
    

    Source

     
     
    题目大意:有一个1000*1000的地图,地图上有一些蛇现在给出蛇的坐标和攻击半径(攻击范围是一个圆),Bill不能从蛇的攻击范围穿过,Bill 必须从西边进入荒漠,
         而从东边离开,可以朝任意方向四个方向走,如果能够完成,按样例格式输出 Bill 进入和离开荒漠的位置,如果有多个位置,输出最北边的位置,
         如果不能完成,输出"Bill will be bitten."
     
    解题思路:这道题吧n条蛇的攻击范围,当成并查集的对象来进行,特别的吧图的最高点(n+1),最低点(0)也加入并查集,如果f[n+1]==f[0],这肯定不能到达,
         否则的话,通过判断左右边界与蛇攻击区域的相交关系,判断边界是否可行,可行的话,在此过程中找出最北方的点,具体见代码注释分析~~~
     
    代码如下:
      1 #include<iostream>
      2 #include<cmath>
      3 #include<cstring>
      4 #include<cstdio>
      5 using namespace std;
      6 #define maxn 1005
      7  
      8 /*-------------上下左右边界判断-------------*/
      9 struct UpDown{
     10     double x, y, area;
     11 }snack[maxn];
     12 struct LeftRight{
     13     double up, down;
     14     int i;
     15 }le[maxn], ri[maxn];
     16  
     17  
     18 int father[maxn], map[maxn][maxn];
     19  
     20  
     21 //----------检查当前出入最高点是否可用--------------------
     22 bool check(LeftRight *p, double x, int n){
     23     for (int i = 0; i < n; i++){
     24         if (p[i].up>x&&p[i].down < x)
     25             return false;
     26     }
     27     return true;
     28 }
     29  
     30 //-------------并查集判断构造的点(包括上下边界)是否连通-------------------
     31 int getf(int x){
     32     return father[x] != x ? father[x] = getf(father[x]) : x;
     33 }
     34  
     35  
     36 int main()
     37 {
     38     int n, i, j;
     39     while (cin >> n){
     40         for (i = 0; i <= n + 1; i++)
     41             father[i] = i;
     42         int L = 0, R = 0;
     43         memset(map, 0, sizeof(map));
     44         for (i = 1; i <= n; i++){
     45             cin >> snack[i].x >> snack[i].y >> snack[i].area;
     46  
     47             //-----------建立上下关系---------------
     48             if (snack[i].y + snack[i].area > 1000)
     49                 map[0][i] = map[i][0] = 1;
     50             if (snack[i].y - snack[i].area < 0)
     51                 map[n + 1][i] = map[i][n + 1] = 1;
     52  
     53             //---------建立左右关系------------------
     54             if (snack[i].x - snack[i].area < 0){
     55                 le[L].up = snack[i].y + sqrt(pow(snack[i].area, 2) - pow(snack[i].x, 2));
     56                 le[L].down = snack[i].y - sqrt(pow(snack[i].area, 2) - pow(snack[i].x, 2));
     57                 le[L++].i = i;
     58             }
     59             if (snack[i].x + snack[i].area >1000){
     60                 ri[R].up = snack[i].y + sqrt(pow(snack[i].area, 2) - pow((1000 - snack[i].x), 2));
     61                 ri[R].down = snack[i].y - sqrt(pow(snack[i].area, 2) - pow((1000 - snack[i].x), 2));
     62                 ri[R++].i = i;
     63             }
     64         }
     65  
     66         //-------------通过圆心判断各区域相交情况-------------------
     67         for (i = 1; i < n; i++)
     68         for (j = i + 1; j <= n; j++){
     69             if (snack[i].area + snack[j].area>sqrt(pow((snack[i].x - snack[j].x), 2) + pow((snack[i].y - snack[j].y), 2)))
     70                 map[i][j] = map[j][i] = 1;
     71         }
     72  
     73         //-----------并查集处理------------------
     74         for (i = 0; i <= n; i++)
     75         for (j = i + 1; j <= n + 1; j++){
     76             if (map[i][j]){
     77                 int x = getf(i), y = getf(j);
     78                 if (x != y)
     79                     father[y] = x;
     80             }
     81         }
     82  
     83  
     84  
     85         if (getf(n + 1) == getf(0))
     86             cout << "Bill will be bitten." << endl;
     87  
     88         else{
     89             double Lflag = -1, Rflag = -1, Lup = 1000, Ldown = 0, Rup = 1000, Rdown = 0;
     90  
     91             //-----------找到最高可用左边界------------------------
     92             for (i = 0; i < L; i++){
     93                 if (getf(le[i].i) == getf(0) && le[i].down < Lup)
     94                     Lup = le[i].down;
     95                 if (getf(le[i].i) == getf(n + 1) && le[i].up >Ldown)
     96                     Ldown = le[i].up;
     97             }
     98  
     99             if (check(le, 1000, L) && Lup == 1000)
    100                 Lflag = 1000;
    101  
    102             for (i = 0; i < L; i++){
    103                 if (le[i].up <= Lup&&le[i].up >= Ldown&&check(le, le[i].up, L) && Lflag < le[i].up)
    104                     Lflag = le[i].up;
    105                 if (le[i].down <= Lup&&le[i].down >= Ldown&&check(le, le[i].down, L) && Lflag < le[i].down)
    106                     Lflag = le[i].down;
    107             }
    108             //----------------------------------------------------------------------
    109  
    110  
    111             //--------------------------===右边界处理-----------------------
    112             for (i = 0; i < R; i++){
    113                 if (getf(ri[i].i) == getf(0) && ri[i].down < Rup)
    114                     Rup = ri[i].down;
    115                 if (getf(ri[i].i) == getf(n + 1) && ri[i].up >Rdown)
    116                     Rdown = ri[i].up;
    117             }
    118             if (check(ri, 1000, R) && Rup == 1000)
    119                 Rflag = 1000;
    120             for (i = 0; i < R; i++){
    121                 if (ri[i].up <= Rup&&ri[i].up >= Rdown&&check(ri, ri[i].up, R) && Rflag < ri[i].up)
    122                     Rflag = ri[i].up;
    123                 if (ri[i].down <= Rup&&ri[i].down >= Rdown&&check(ri, ri[i].down, R) && Rflag < ri[i].down)
    124                     Rflag = ri[i].down;
    125             }
    126             if (L == 0)
    127                 Lflag = 1000;
    128             if (R == 0)
    129                 Rflag = 1000;
    130             if (Rflag < 0 || Lflag < 0)
    131                 cout << "Bill will be bitten." << endl;
    132             else
    133                 printf("Bill enters at (0.00, %.2lf) and leaves at (1000.00, %.2lf).
    ", Lflag, Rflag);
    134         }
    135     }
    136     return 0;
    137 }
    View Code
     
  • 相关阅读:
    关于Javascript的有趣的3个小知识
    linux支持串口(serial)登录配置方法
    Silicom Linux BypassSD Control Utilitybypass command
    USB隨身碟版的Clonezilla live
    如何將Clonezilla live放到一個已經有其他作業系統存在的硬碟中
    clonezilla for usb as ghost or backup,auto ghost,auto backup(再生龙一键还原(备份)的制作)
    典型PC机上各种操作的近似时间
    linux网络问题子网掩码与网关不在同一段的处理
    Linux family member.(AS/ES/WS)
    华为交换机常用命令
  • 原文地址:https://www.cnblogs.com/zyxStar/p/4581022.html
Copyright © 2020-2023  润新知