Jack Straws
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 2911 | Accepted: 1322 |
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.
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
Source
判断两线段相交 + 并查集。
一开始以为是简单的判断两线段相交问题,提交WA,后来发现还要用到并查集,因为这道题允许2条线段通过其他线段间接的相交,这就要求通过亲戚关系查找2条线段是否在同一集合。我一看正好是下学期数据结构的知识,就趁机熟悉了一遍。自己敲上了并查集的模板,判断两线段相交直接套用了模板,提交AC。
并查集模板:
1 int UFS_NUM; //并查集中元素总数
2 typedef struct node{
3 int data; //节点对应的编号
4 int rank; //节点对应秩
5 int parent; //节点对应的双亲下标
6 }UFSTree; //并查集树的节点类型
7 void MAKE_SET(UFSTree t[]) //初始化并查集树
8 {
9 int i;
10 for(i=1;i<=UFS_NUM;i++){
11 t[i].data = i; //数据为该点编号
12 t[i].rank = 0; //秩初始化为0
13 t[i].parent = i; //双亲初始化为指向自己
14 }
15 }
16 int FIND_SET(UFSTree t[],int x) //在x所在的子树中查找集合编号
17 {
18 if(t[x].parent == x) //双亲是自己
19 return x; //双亲是自己,返回 x
20 else //双亲不是自己
21 return FIND_SET(t,t[x].parent); //递归在双亲中查找x
22 }
23 void UNION(UFSTree t[],int x,int y) //将x和y所在的子树合并
24 {
25 x = FIND_SET(t,x); //查找 x 所在分离集合树的编号
26 y = FIND_SET(t,y); //查找 y 所在分离集合树的编号
27 if(t[x].rank > t[y].rank) //y 节点的秩小于 x节点的秩
28 t[y].parent = x; //将 y 连接到 x 节点上,x 作为 y 的双亲节点
29 else{ //y 节点的秩大于等于 x 节点的秩
30 t[x].parent = y; //将 x 连接到 y 节点上,y 作为 x 的双亲节点
31 if(t[x].rank==t[y].rank) //x 和 y的双亲节点秩相同
32 t[y].rank++; //y 节点的秩增 1
33 }
34 }
题目代码:
1 #include <iostream>
2 using namespace std;
3 /*--------- 并查集 模板 ------------*/
4 int UFS_NUM; //并查集中元素总数
5 typedef struct node{
6 int data; //节点对应的编号
7 int rank; //节点对应秩
8 int parent; //节点对应的双亲下标
9 }UFSTree; //并查集树的节点类型
10 void MAKE_SET(UFSTree t[]) //初始化并查集树
11 {
12 int i;
13 for(i=1;i<=UFS_NUM;i++){
14 t[i].data = i;
15 t[i].rank = 0;
16 t[i].parent = i;
17 }
18 }
19 int FIND_SET(UFSTree t[],int x) //在x所在的子树中查找集合编号
20 {
21 if(t[x].parent == x)
22 return x;
23 else
24 return FIND_SET(t,t[x].parent);
25 }
26 void UNION(UFSTree t[],int x,int y) //将x和y所在的子树合并
27 {
28 x = FIND_SET(t,x);
29 y = FIND_SET(t,y);
30 if(t[x].rank > t[y].rank)
31 t[y].parent = x;
32 else{
33 t[x].parent = y;
34 if(t[x].rank==t[y].rank)
35 t[y].rank++;
36 }
37 }
38
39 /*--------- 判断两线段相交 模板 ------------*/
40 const double eps=1e-10;
41 struct point { double x, y; };
42 double min(double a, double b) { return a < b ? a : b; }
43 double max(double a, double b) { return a > b ? a : b; }
44 bool inter(point a, point b, point c, point d){
45 if ( min(a.x, b.x) > max(c.x, d.x) ||
46 min(a.y, b.y) > max(c.y, d.y) ||
47 min(c.x, d.x) > max(a.x, b.x) ||
48 min(c.y, d.y) > max(a.y, b.y) ) return 0;
49 double h, i, j, k;
50 h = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
51 i = (b.x - a.x) * (d.y - a.y) - (b.y - a.y) * (d.x - a.x);
52 j = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x);
53 k = (d.x - c.x) * (b.y - c.y) - (d.y - c.y) * (b.x - c.x);
54 return h * i <= eps && j * k <= eps;
55 }
56
57 /*---------- 代码实现 -----------*/
58 struct line
59 {
60 point p1;
61 point p2;
62 };
63 int main()
64 {
65 int n;
66 UFSTree t[105];
67 while(cin>>n){
68 if(n==0) break;
69 UFS_NUM = n;//确定并查集树中元素总数
70 MAKE_SET(t); //初始化并查集
71 line l[15];
72 for(int i=1;i<=n;i++)
73 cin>>l[i].p1.x>>l[i].p1.y>>l[i].p2.x>>l[i].p2.y;
74 for(int i=1;i<=n;i++) //根据关系生成关系树
75 for(int j=1;j<=n;j++){
76 if(i==j) continue;
77 if(inter(l[i].p1,l[i].p2,l[j].p1,l[j].p2)){ //如果相交,有亲戚关系
78 UNION(t,i,j); //合并相关集合
79 }
80 }
81 int l1,l2;
82 while(cin>>l1>>l2){
83 if(l1==0 && l2==0)
84 break;
85 l1 = FIND_SET(t,l1);
86 l2 = FIND_SET(t,l2);
87 if(l1 == l2)
88 cout<<"CONNECTED"<<endl;
89 else
90 cout<<"NOT CONNECTED"<<endl;
91 }
92 }
93 return 0;
94 }