[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).\n", Lflag, Rflag);
134         }
135     }
136     return 0;
137 }
View Code

 

 
posted @ 2015-06-16 15:53  繁夜  阅读(447)  评论(0编辑  收藏  举报