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 }
在进行合并操作时,因为合并的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 }
完整代码:
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 }
----------------------------------------------------------------------------------------------------------------转载请说明出处----------------------------------------------------------------------------------------------------------------------
你要做一个不动声色的大人了。不准情绪化,不准偷偷想念,不准回头看。去过自己另外的生活。你要听话,不是所有的鱼都会生活在同一片海里。
————————村上春树