POJ-1127 Jack Straws

Jack Straws
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 2624   Accepted: 1183

Description

In the game of Jack Straws, a number of plastic or wooden "straws" are dumped on the table and players try to remove them one-by-one without disturbing the other straws. Here, we are only concerned with if various pairs of straws are connected by a path of touching straws. You will be given a list of the endpoints for some straws (as if they were dumped on a large piece of graph paper) and then will be asked if various pairs of straws are connected. Note that touching is connecting, but also two straws can be connected indirectly via other connected straws.

Input

Input consist multiple case,each case consists of multiple lines. The first line will be an integer n (1 < n < 13) giving the number of straws on the table. Each of the next n lines contain 4 positive integers,x1,y1,x2 and y2, giving the coordinates, (x1,y1),(x2,y2) of the endpoints of a single straw. All coordinates will be less than 100. (Note that the straws will be of varying lengths.) The first straw entered will be known as straw #1, the second as straw #2, and so on. The remaining lines of the current case(except for the final line) will each contain two positive integers, a and b, both between 1 and n, inclusive. You are to determine if straw a can be connected to straw b. When a = 0 = b, the current case is terminated.

When n=0,the input is terminated.

There will be no illegal input and there are no zero-length straws.

Output

You should generate a line of output for each line containing a pair a and b, except the final line where a = 0 = b. The line should say simply "CONNECTED", if straw a is connected to straw b, or "NOT CONNECTED", if straw a is not connected to straw b. For our purposes, a straw is considered connected to itself.

Sample Input

7
1 6 3 3 
4 6 4 9 
4 5 6 7 
1 4 3 5 
3 5 5 5 
5 2 6 3 
5 4 7 2 
1 4 
1 6 
3 3 
6 7 
2 3 
1 3 
0 0

2
0 2 0 0
0 0 0 1
1 1
2 2
1 2
0 0

0

Sample Output

CONNECTED 
NOT CONNECTED 
CONNECTED 
CONNECTED 
NOT CONNECTED 
CONNECTED
CONNECTED
CONNECTED
CONNECTED
  1 /* 功能Function Description:  POJ-1127   
  2    开发环境Environment:       DEV C++ 4.9.9.1
  3    技术特点Technique:
  4    版本Version:
  5    作者Author:                可笑痴狂
  6    日期Date:                   20120817
  7    备注Notes:
  8     题意:
  9     首先给出一个n,表示共有n条边,下面n行(编号1-n)每行给出4个数分别表示起始点的横纵坐标
 10     以及终止点的横纵坐标。接下来的若干行为查询条件,要你输出查询的两条边是否有关系
 11     (即直接相交或间接相交)。
 12     思路:
 13     线段相交判断+并查集
 14     判断第i条和第j条线段是否相交的充要条件是:
 15         第i条线段的两端点在第j条线段所在直线的两侧 且 第j条线段的两端点在第i条线段所在直线的两侧 
 16         (端点也可以位于相应的直线上)
 17         + 特殊情况的判断-----共线的情况
 18 
 19 */
 20 
 21 //代码一:----wrong answer -----纠结一天了也找不到原因 
 22 #include<stdio.h>
 23 
 24 int set[30];
 25 double coord[30][4];  //coord[i][0]、coord[i][1]、coord[i][2]、coord[i][3]分别存储第i条线段两端点的坐标: x1,y1,x2,y2
 26 
 27 int judge(int i,int j)    //判断第i条和第j条线段是否相交的充要条件是: 第i条线段的两端点在第j条线段所在直线的两侧 且 第j条线段的两端点在第i条线段所在直线的两侧
 28 {
 29     int flag1,flag2;
 30     double max1,min1,max2,min2;
 31     flag1=flag2=0;
 32 
 33     //共线的情况
 34     if((coord[i][3]-coord[i][1])*(coord[j][2]-coord[j][0])-(coord[j][3]-coord[j][1])*(coord[i][2]-coord[i][0])<0.0000001)    //j与i 平行
 35     {
 36         max1=coord[i][0]>coord[i][2]?coord[i][0]:coord[i][2];
 37         min1=coord[i][0]<coord[i][2]?coord[i][0]:coord[i][2];
 38         max2=coord[j][0]>coord[j][2]?coord[j][0]:coord[j][2];
 39         min2=coord[j][0]<coord[j][2]?coord[j][0]:coord[j][2];
 40         if(coord[i][0]==coord[i][2])  //直线i与x轴垂直 
 41         {
 42             if(coord[j][0]==coord[i][0])    //直线i与直线j所在直线重合
 43                 if(max1>=min2&&max1<=max2||min1>=min2&&min1<=max2||max2>=min1&&max2<=max1||min2>=min1&&min2<=max1)
 44                     return 1;
 45         }
 46         else    //不与x轴垂直的话直接判断j的两个端点是否在直线i上就可以了
 47         {
 48             if(((coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[j][0]+coord[i][1]-(coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[i][0]-coord[j][1])<0.0000001)
 49                 if(max1>=min2&&max1<=max2||min1>=min2&&min1<=max2||max2>=min1&&max2<=max1||min2>=min1&&min2<=max1)
 50                     return 1;
 51         }
 52     }
 53     //不共线的情况下判断线段j是否在线段i所在直线的两侧
 54     if(coord[i][0]==coord[i][2])  //直线i与x轴垂直
 55     {
 56         if((coord[j][0]-coord[i][0])*(coord[j][2]-coord[i][0])<=0)
 57             flag1=1;
 58     }
 59     else
 60     {
 61         if(((coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[j][0]+coord[i][1]-(coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[i][0]-coord[j][1])*
 62             ((coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[j][2]+coord[i][1]-(coord[i][3]-coord[i][1])/(coord[i][2]-coord[i][0])*coord[i][0]-coord[j][3])<=0)
 63             flag1=1;
 64     }
 65 
 66     //判断线段i是否在线段j所在直线的两侧
 67     if(coord[j][0]==coord[j][2])  //直线j与x轴垂直
 68     {
 69         if((coord[i][0]-coord[j][0])*(coord[i][2]-coord[j][0])<=0)
 70             flag2=1;
 71     }
 72     else
 73     {
 74         if(((coord[j][3]-coord[j][1])/(coord[j][2]-coord[j][0])*coord[i][0]+coord[j][1]-(coord[j][3]-coord[j][1])/(coord[j][2]-coord[j][0])*coord[j][0]-coord[i][1])*
 75             ((coord[j][3]-coord[j][1])/(coord[j][2]-coord[j][0])*coord[i][2]+coord[j][1]-(coord[j][3]-coord[j][1])/(coord[j][2]-coord[j][0])*coord[j][0]-coord[i][3])<=0)
 76             flag2=1;
 77     }
 78     if(flag1&&flag2)
 79         return 1;
 80     else
 81         return 0;
 82 }
 83 
 84 int find(int i)
 85 {
 86     if(i!=set[i])                //--------压缩路径
 87         set[i]=find(set[i]);
 88     return set[i];  //注意这里不能写成i,就这一点写错了调试了半天
 89 }
 90 
 91 void merge(int i,int j)
 92 {
 93     i=find(i);
 94     j=find(j);
 95     if(i!=j)
 96         set[i]=j;
 97 }
 98 
 99 int main()
100 {
101     int n,i,j;
102     while(scanf("%d",&n),n)
103     {
104         for(i=1;i<=n;++i)
105             set[i]=i;
106         for(i=1;i<=n;++i)
107             scanf("%lf%lf%lf%lf",&coord[i][0],&coord[i][1],&coord[i][2],&coord[i][3]);
108         for(i=1;i<n;++i)
109         {
110             for(j=i+1;j<=n;++j)
111             {
112                 if(judge(i,j))
113                 {
114                     merge(i,j);
115                 }
116             }
117         }
118         while(scanf("%d%d",&i,&j)&&(i||j))
119         {
120             if(find(i)==find(j))
121                 printf("CONNECTED\n");
122             else
123                 printf("NOT CONNECTED\n");
124         }
125     }
126     return 0;
127 }
128 
129 
130 //代码二: ----转
131 #include<stdio.h>
132 #include<math.h>
133  
134 #define MAX 15
135  
136 /* 定义点信息,x为横坐标,y为纵坐标 */
137 typedef struct
138 {
139     double x;
140     double y;
141 }point;
142  
143 /* 定义边信息,s为起始节点,e为终止节点 */
144 typedef struct
145 {
146     point s;
147     point e;
148 }line;
149  
150 line p[MAX];
151 int father[MAX];
152 int rank[MAX];
153  
154 /* 初始化集合 */
155 void Make_Set(int x)
156 {
157     father[x] = x;
158     rank[x] = 0;
159 }
160  
161 /* 查找x元素所在的集合,回溯时压缩路径 */
162 int Find_Set(int x)
163 {
164     if (x != father[x])
165     {
166         father[x] = Find_Set(father[x]);
167     }
168     return father[x];
169 }
170  
171 /* 合并x,y所在的集合 */
172 void Union(int x, int y)
173 {
174     if (x == y) return;
175     if (rank[x] > rank[y])
176     {
177         father[y] = x;
178     }
179     else
180     {
181         if (rank[x] == rank[y])
182         {
183             rank[y]++;
184         }
185         father[x] = y;
186     }
187 }
188  
189 /* 最大值函数 */
190 double max(double x, double y)
191 {
192     return x > y ? x : y;
193 }
194  
195 /* 最小值函数 */
196 double min(double x, double y)
197 {
198     return x < y ? x : y;
199 }
200  
201 /* 叉积 (a-c)x(b-c) */
202 double multiply(point a, point b, point c)
203 {
204     return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);
205 }
206  
207 /* 跨立判断 */
208 int intersect(line u, line v)
209 {
210     return (( max(u.s.x, u.e.x) >= min(v.s.x, v.e.x)) 
211     && (max(v.s.x, v.e.x) >= min(u.s.x, u.e.x)) 
212     && (max(u.s.y, u.e.y) >= min(v.s.y, v.e.y)) 
213     && (max(v.s.y, v.e.y) >= min(u.s.y, u.e.y)) 
214     && (multiply(v.s, u.e, u.s) * multiply(u.e, v.e, u.s) >= 0) 
215     && (multiply(u.s, v.e, v.s) * multiply(v.e, u.e, v.s) >= 0));
216 }
217  
218 int main()
219 {
220     int n, i, j;
221     int a, b, x, y;
222     while(1)
223     {
224         scanf("%d", &n);
225         if (n == 0) break;
226         /* 初始化集合 */
227         for(i = 1; i <= n; i++)
228         {
229             Make_Set(i);
230         }
231         /* 读入边信息 */
232         for(i = 1; i <= n; i++)
233         {
234             scanf("%lf%lf%lf%lf", &p[i].s.x, &p[i].s.y, &p[i].e.x, &p[i].e.y);
235         }
236         /* 处理每条边,如果相交就合并 */
237         for(i = 1; i <= n; i++)
238         {
239             for(j = 1; j <= n; j++)
240             {
241                 if(i != j && intersect(p[i], p[j]))
242                 {
243                     x = Find_Set(i);
244                     y = Find_Set(j);
245                     Union(x,y);
246                 }
247             }
248         }
249         /* 进行查询 */
250         while(1)
251         {
252             scanf("%d %d", &a, &b);
253             if (a + b == 0) break;
254             /* 自己和自己肯定有关系 */
255             if(a == b)
256             {
257                 printf("CONNECTED\n");
258             }
259             else
260             {
261                 /* 若在一个集合则两边有关系 */
262                 x = Find_Set(a);
263                 y = Find_Set(b);
264                 if(x == y)
265                 {
266                     printf("CONNECTED\n");
267                 }
268                 else
269                 {
270                     printf("NOT CONNECTED\n");
271                 }
272             }
273         }
274     }
275     //system("pause");
276     return 0;
277 }

 

你可能感兴趣的:(poj)