http://poj.org/problem?id=1703
题意 :有两个黑帮团伙。有n个团伙成员,现在并不知道他们分别属于哪个团伙。给你一些信息,信息中包含两个人的编号,表示这两个人分属不同团伙,然后给你两个人的编号,问你他们俩是不是属于同一个团伙。
思路 : 并查集。因为这个题给出的每个关系都代表着两个人属于不同的团伙,所以没办法像普通的并查集那样,只用两个集合就行,例如,给你(1,2)(5,6)(1,5),根据关系我们可以知道2,5属于一个团伙,1,6属于一个团伙,但是你并没有办法表示。书上介绍了一种常用的做法:只要两者关系确定了,就将他们放入同一集合中,再另外增加一个关系数组father[]来表示该结点与其父亲的关系,0表示是同一类,1表示是不同团伙,初始时集合只有自己一个元素,所以father的初始值置为1。
#include<iostream> #include<string.h> #include<stdio.h> #include<stdlib.h> using namespace std; int pre[100010];//代表着父亲结点,如果D后边是a b,则pre[b]=a ; int father[100010] ;//代表着这个点和父亲结点的关系,是属于同一类还是不同团伙 int m,n ; int find(int x) { int temp = pre[x] ; if (pre[x] == x) return x ; pre[x] = find(pre[x]); father[x] = father[x] == father[temp] ? 0 : 1 ;//等于0表示属于同一类 return pre[x]; } void unionn(int x,int y,int xx,int yy) { pre[xx] = yy ; father[xx] = father[x] == father[y] ? 1 : 0 ; } int main() { int t ; scanf("%d",&t) ; int m,n ; while(t--) { scanf("%d %d",&n,&m) ; for(int i = 1 ; i <= n ; i++) { pre[i]=i; father[i] = 0 ; } char x ; int a,b ; for(int i = 1 ; i <= m ; i++) { scanf("\n%c %d %d",&x,&a,&b) ; int aa = find(a),bb = find(b); if(x == 'D') { if(aa != bb) unionn(a,b,aa,bb) ; } if(x == 'A') { if(aa != bb)//父亲不同,说明此时还没有建立关系 { printf("Not sure yet.\n"); continue ; } if(father[a] == father[b])//父亲相同,在比较两者和父亲的关系 { printf("In the same gang.\n") ; continue ; } printf("In different gangs.\n"); continue ; } } } return 0; }