POJ1703 Find them, Catch them(并查集)

题目链接:http://poj.org/problem?id=1703

塔都市的警察局决定以混乱为目标,作为启动行动,扎根城市中的两个帮派,Gang Dragon和Gang Snake。
但是,警方首先需要确定犯罪分子属于哪个团伙。目前的问题是,两名罪犯; 他们属于同一个氏族吗?
您必须根据不完整的信息做出判断。(因为歹徒总是暗中行动。)
假设N(N <= 10 ^ 5)罪犯目前在塔都市,编号从1到N.当然,他们中至少有一人属于Gang Dragon,
同样为Gang Snake。您将按顺序给出M(M <= 10 ^ 5)个消息,它们分为以下两种:
1。D [a] [b]
其中[a]和[b]是两个罪犯的数字,以及他们属于不同的帮派。
2. A [a] [b]
其中[a]和[b]是两个罪犯的数量。这需要您决定a和b是否属于同一个团伙。
输入
输入的第一行包含单个整数T(1 <= T <= 20),即测试用例的数量。然后是T案例。
每个测试用例以具有两个整数N和M的行开始,接着是M行,每行包含如上所述的一个消息。
产量
对于每种情况下的每条消息“A [a] [b]”,您的程序应根据之前获得的信息进行判断。
样本输入
1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4
样本输出
Not sure yet.
In different gangs.
In the same gang.
这个题目也是典型的并查集的题目,因为总共只有两个黑帮,所以可以用两个集合来求解。当让,用一个集合也可以。
只是要对relation进行细心设置(可以设置relatiin:0表示关系相同,1为关系不同)。在对一个元素执行Find()操作时,如果它与父亲结点realtion相同,父亲结点与根结点relation相同,那么该元素与根结点关系也相同。否则是不同的。
 1 int DisJoinSet ::Find(int x)
 2 {
 3     int temp = tree[x].parent;//temp x的父亲结点
 4     if(x != tree[x].parent)
 5     {
 6         tree[x].parent = Find(tree[x].parent);//递归在双亲中找x
 7     // tree[temp].relation必为temp结点(x的父节点)与根节点的关系,tree[x].relation最初为x与temp的关系,
 8     // tree[x].relation == tree[temp].relation意味着tree[x].relation和tree[temp].relation同为1,或者同为0
 9     // 如果tree[x].relation和tree[temp].relation同为1,意味着根节点与temp不同类,temp与x不同类,总共只有2个集合,x与根节点必定同类。
10     // 如果tree[x].relation和tree[temp].relation同为0,意味着根节点与temp同类,temp与x同类,x与根节点也必定同类。
11         if(tree[x].relation == tree[temp].relation)
12         {
13             tree[x].relation = 0;
14         }
15     // tree[x].relation != tree[temp].relation意味着tree[x].relation和tree[temp].relation一个为1,一个为0,
16     // 如果tree[temp].relation为false,tree[temp].relation为1,意味着根节点和temp同类,temp与x不同类,那么x与根节点必然不同类
17     // 如果tree[temp].relation为true,tree[x].relation为0,意味着根节点和temp不同类,temp与x同类,那么x与根节点必然不同类
18         else
19         {
20             tree[x].relation = 1;
21         }    
22         return tree[x].parent;// 返回根节点下标
23     }
24     else
25     {
26         return x;
27     }
28 }
View Code
在进行合并操作时,因为合并的x和y是属于不同集合的,所以和上面一样的推理。
 1 void DisJoinSet ::Union(int x,int y)
 2 {
 3     int rootx = Find(x);
 4     int rooty = Find(y);
 5     if(rootx == rooty)
 6     {
 7         return ;
 8     }
 9     if(tree[rootx].rank > tree[rooty].rank)
10     {
11         tree[rooty].parent = rootx;
12         // 此时rooty与其根结点rootx的关系如何确定?因为Find方法也在进行路径压缩,x的父节点是rootx,y的父节点的rooty
13         // 如果tree[x].relation和tree[y].relation均为1,说明x和rootx不同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx不同类;
14         // 如果tree[x].relation和tree[y].relation均为0,说明x和rootx同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx不同类
15         if(tree[x].relation == tree[y].relation)
16         {
17             tree[rooty].relation = 1;
18         }
19         // 如果tree[x].relation为1,tree[y].relation为0,说明x和rootx不同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx必同类;
20         // 如果tree[x].relation为0,tree[y].relation为1,说明x和rootx同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx必同类;
21         else
22         {
23             tree[rooty].relation = 0;
24         }
25     }
26     else
27     {
28         tree[rootx].parent = rooty;
29         if(tree[rootx].rank == tree[rooty].rank)
30         {
31             tree[rooty].rank ++;
32         }
33         // 此时rooty与其根结点rootx的关系如何确定?因为Find方法也在进行路径压缩,x的父节点是rootx,y的父节点的rooty
34         // 如果relation[x]和relation[y]均为true,说明x和rootx不同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx不同类;
35         // 如果relation[x]和relation[y]均为false,说明x和rootx同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx不同类
36         if(tree[x].relation == tree[y].relation)
37         {
38             tree[rootx].relation = 1;
39         }
40         // 如果tree[x].relation为1,tree[y].relation为0,说明x和rootx不同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx必同类;
41         // 如果tree[x].relation为0,tree[y].relation为1,说明x和rootx同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx必同类;
42         else
43         {
44             tree[rootx].relation = 0;
45         }
46     }
47 }
View Code

完整代码:

  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<vector>
  6 #include<stack>
  7 #include<map>
  8 #include<set>
  9 #include<list>
 10 #include<queue>
 11 #include<string>
 12 #include<algorithm>
 13 #include<iomanip>
 14 using namespace std;
 15 
 16 struct node
 17 {
 18     int no;
 19     int rank;
 20     int parent;
 21     int relation;
 22 };
 23 
 24 class DisJoinSet
 25 {
 26     protected:
 27         int n;
 28         node *tree;
 29     public :
 30         DisJoinSet(int n);
 31         ~DisJoinSet();
 32         void Init();
 33         void Union(int x,int y);
 34         int Find(int x);
 35         bool itsSame(int x,int y);
 36 };
 37 
 38 DisJoinSet ::DisJoinSet(int n)
 39 {
 40     this->n = n;
 41     tree = new node[n+1];
 42     Init();
 43 }
 44 
 45 DisJoinSet ::~DisJoinSet()
 46 {
 47     delete []tree;
 48 }
 49 
 50 void DisJoinSet::Init()
 51 {
 52     for(int i = 1; i <= n; i ++)
 53     {
 54         tree[i].no = i;
 55         tree[i].rank = 0;
 56         tree[i].parent = i;
 57         tree[i].relation = 0;
 58     }
 59 }
 60 
 61 int DisJoinSet ::Find(int x)
 62 {
 63     int temp = tree[x].parent;//temp x的父亲结点
 64     if(x != tree[x].parent)
 65     {
 66         tree[x].parent = Find(tree[x].parent);//递归在双亲中找x
 67     // tree[temp].relation必为temp结点(x的父节点)与根节点的关系,tree[x].relation最初为x与temp的关系,
 68     // tree[x].relation == tree[temp].relation意味着tree[x].relation和tree[temp].relation同为1,或者同为0
 69     // 如果tree[x].relation和tree[temp].relation同为1,意味着根节点与temp不同类,temp与x不同类,总共只有2个集合,x与根节点必定同类。
 70     // 如果tree[x].relation和tree[temp].relation同为0,意味着根节点与temp同类,temp与x同类,x与根节点也必定同类。
 71         if(tree[x].relation == tree[temp].relation)
 72         {
 73             tree[x].relation = 0;
 74         }
 75     // tree[x].relation != tree[temp].relation意味着tree[x].relation和tree[temp].relation一个为1,一个为0,
 76     // 如果tree[temp].relation为false,tree[temp].relation为1,意味着根节点和temp同类,temp与x不同类,那么x与根节点必然不同类
 77     // 如果tree[temp].relation为true,tree[x].relation为0,意味着根节点和temp不同类,temp与x同类,那么x与根节点必然不同类
 78         else
 79         {
 80             tree[x].relation = 1;
 81         }    
 82         return tree[x].parent;// 返回根节点下标
 83     }
 84     else
 85     {
 86         return x;
 87     }
 88 }
 89 
 90 void DisJoinSet ::Union(int x,int y)
 91 {
 92     int rootx = Find(x);
 93     int rooty = Find(y);
 94     if(rootx == rooty)
 95     {
 96         return ;
 97     }
 98     if(tree[rootx].rank > tree[rooty].rank)
 99     {
100         tree[rooty].parent = rootx;
101         // 此时rooty与其根结点rootx的关系如何确定?因为Find方法也在进行路径压缩,x的父节点是rootx,y的父节点的rooty
102         // 如果tree[x].relation和tree[y].relation均为1,说明x和rootx不同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx不同类;
103         // 如果tree[x].relation和tree[y].relation均为0,说明x和rootx同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx不同类
104         if(tree[x].relation == tree[y].relation)
105         {
106             tree[rooty].relation = 1;
107         }
108         // 如果tree[x].relation为1,tree[y].relation为0,说明x和rootx不同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx必同类;
109         // 如果tree[x].relation为0,tree[y].relation为1,说明x和rootx同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx必同类;
110         else
111         {
112             tree[rooty].relation = 0;
113         }
114     }
115     else
116     {
117         tree[rootx].parent = rooty;
118         if(tree[rootx].rank == tree[rooty].rank)
119         {
120             tree[rooty].rank ++;
121         }
122         // 此时rooty与其根结点rootx的关系如何确定?因为Find方法也在进行路径压缩,x的父节点是rootx,y的父节点的rooty
123         // 如果relation[x]和relation[y]均为true,说明x和rootx不同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx不同类;
124         // 如果relation[x]和relation[y]均为false,说明x和rootx同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx不同类
125         if(tree[x].relation == tree[y].relation)
126         {
127             tree[rootx].relation = 1;
128         }
129         // 如果tree[x].relation为1,tree[y].relation为0,说明x和rootx不同类,y和rooty同类,而已知x和y不同类,因此rooty和rootx必同类;
130         // 如果tree[x].relation为0,tree[y].relation为1,说明x和rootx同类,y和rooty不同类,而已知x和y不同类,因此rooty和rootx必同类;
131         else
132         {
133             tree[rootx].relation = 0;
134         }
135     }
136 }
137 
138 
139 bool DisJoinSet::itsSame(int x,int y)
140 {
141     return (tree[x].relation == tree[y].relation);
142 }
143 
144 
145 int main()
146 {
147     int T;
148     while(scanf("%d",&T) !=EOF )// 没有EOF 会 OLE
149     {
150         if(T == 0)break;
151         for(int i = 0; i < T; i++)
152         {
153             int N;
154             int M;
155             scanf("%d%d",&N,&M);
156             DisJoinSet dis(N);
157             char s1[2];
158             int s2,s3;
159             for(int i= 0; i < M ;i ++)
160             {
161                 scanf("%s%d%d",s1,&s2,&s3);
162                 int pa = dis.Find(s2);
163                 int pb = dis.Find(s3);
164                 if(s1[0] == 'A')
165                 {
166                     if(pa != pb)
167                     {
168                         cout<<"Not sure yet."<<endl;
169                     }
170                     else if(dis.itsSame(s2,s3) )
171                     {
172                         cout<<"In the same gang."<<endl;
173                     }
174                     else//根相同 但是rela不同,说明不再统一gangs
175                     {
176                         cout<<"In different gangs."<<endl;
177                     }
178                 }
179                 if(s1[0]=='D')
180                 {
181                     if(pa != pb)
182                     {
183                         dis.Union(s2,s3);
184                     }
185                     
186                 }
187             }
188         }
189     }
190     return 0;
191 }
View Code

猜你喜欢

转载自www.cnblogs.com/ygsworld/p/11141050.html