[POJ 2588]--Snakes(并查集)
题目链接:http://poj.org/problem?id=2588
Snakes
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 }
如果这是你所爱的,就不要让自己后悔~~~