[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

Waterloo local 2000.01.29

题目大意:有一个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 }

时间: 2024-11-05 21:39:02

[POJ 2588]--Snakes(并查集)的相关文章

POJ 2492 (简单并查集) A Bug&#39;s Life

题意:有编号为1~n的虫子,开始假设这种昆虫是异性恋.然后已知xi 和 yi进行交配,根据已知情况分析能否推理出其中是否有同性恋 这道题和 POJ 1182 食物链 十分相似,不过在更新与父节点关系的时候要简单一些 sex数组保存的是与父节点的性别关系,如果与父节点是同性,则为0,否则是1 每次路径压缩的同时要更新sex[a] = (sex[a] + sex[temp]) % 2; 还有就是如果x 和 y 不在一个集合,两棵树进行合并的时候,考虑x px y py 四者之间的关系,有 paren

POJ - Colored Sticks - 并查集+字典树

这道题主要还是要判断是不是欧拉图 说白了就是能不能这幅图能不能用一笔画下来,那么就可以知道了,如果是一个环状的,说明奇数度就不存在,否则就只能用两个奇数度(起点终点)//我的理解这是 只需要用字典树将单词变为对应的一个数字,然后并查集操作就可以,需要维护一个度变量 #include<stdio.h> #include<string.h> int du[500010],p[500010]; int tot=1; struct tree { tree *next[30]; int id

poj 2513 欧拉回路+并查集判断是否联通+Trie树

http://poj.org/problem?id=2513 最初看到 第一感觉---map  一看250000的数据量 果断放弃 然后记得以前看过,trie代替map,尤其当数据量特别大的时候 学到了: 1.Trie代替map的思想,可以在单词结尾的tree[i][tk]  这个i作为字符串对应的int值 ,当然这个int值也可以用于建立并查集 2.接上,通过并查集判断,所有的点在同一个集合图就是联通的,否则不联通,注意tree[i][tk]>0 表示是单词结尾, x=Find(x);//这句

POJ 1182 食物链 [并查集 带权并查集 开拓思路]

传送门 P - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1182 Appoint description:  System Crawler  (2015-01-27) Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物

Poj(1703),种类并查集

题目链接:http://poj.org/problem?id=1703 已经不是第一次接触种类并查集了,直到今天才搞懂. 感谢红黑联盟,感谢杰哥!!! 每个节点只要关系确定,不管是不是同一个集合里面,都把他们放到一个集合里面,用一个rank[]数组记录他们与根节点的关系,比较神奇的地方有两处: 1.find函数里面,因为find是递归写的,不断往上找,不断更新rank[x](与根节点的关系),这个%k,也是很牛逼的,2种类型,标号只有01: 2.Union函数里面,更新rank[fy],rank

poj 2513 欧拉回路+并查集推断是否联通+Trie树

http://poj.org/problem? id=2513 最初看到 第一感觉---map  一看250000的数据量 果断放弃 然后记得曾经看过.trie取代map.尤其当数据量特别大的时候 学到了: 1.Trie取代map的思想,能够在单词结尾的tree[i][tk]  这个i作为字符串相应的int值 .当然这个int值也能够用于建立并查集 2.接上.通过并查集推断.全部的点在同一个集合图就是联通的,否则不联通,注意tree[i][tk]>0 表示是单词结尾. x=Find(x);//这

Poj(1182),种类并查集

题目链接:http://poj.org/problem?id=1182 再次熟练种类并查集,又积累点经验,和技巧,rank 0 2 1 先计算father[x] ,再更新rank[x]; #include <stdio.h> int father[50010]; int rank[50010]; int Find_Set (int x) { int tmp; if(x!=father[x]) { tmp = father[x]; father[x] = Find_Set(father[x]);

poj 1182 (关系并查集) 食物链

题目传送门:http://poj.org/problem?id=1182 这是一道关系型并查集的题,对于每个动物来说,只有三种情况:同类,吃与被吃: 所以可以用0,1,2三个数字代表三种情况,在使用并查集的时候再多加一个关系数组,初始时全部赋值为0 然后就是在进行并查集的每一步时加入关系的改变, 如果祖先节点相同,说明两者之间的关系已经出现,是已知的,判断两者关系之和与给的d-1是否相同 祖先节点不同,说明在此之前两者的关系还未知,就赋予关系 噢 对了 poj 上的这题要单组输入,多组会wa c

[POJ 2588] Snakes

同swustoj 8 Snakes Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1015   Accepted: 341 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