Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 21755 | Accepted: 6471 |
Description
Input
Output
Sample Input
1 5 5 A 1 2 D 1 2 A 1 2 D 2 4 A 1 4
Sample Output
Not sure yet.
In different gangs.
In the same gang.
代码一:
1 /* 功能Function Description: POJ-1703 并查集的应用的扩展 2 开发环境Environment: DEV C++ 4.9.9.1 3 技术特点Technique: 4 版本Version: 5 作者Author: 可笑痴狂 6 日期Date: 20120808 7 备注Notes: 8 【转】 9 解析:并查集的题目,并查集的拓展。 10 一般的思路是先初始化,各个数自成一个组,然后是两个gangs自成一个组, 11 但由于两个给定元素有三种关系: In the same gang; In different gangs; Not sure yet; 12 采用此模型的缺点是判断两个元素关系还未确定这种情况比较复杂,故模型需要改进。本题的正确模型是将已经确定关系的元素组成一个集合, 13 然后利用两个元素的 father是同一个来确定这两个元素之间的关系。father[a]中存放的是a的根结点,rank中存放的是father[a]与a的关系, 14 0表示两者不在同一个gangs中,1表示两者在同一个gangs中。具体的程序还是沿袭了并查集的Make_Set()、Find_Set()、 Union_Set() 15 的三步骤。 16 心得:并查集有三步是必须的:Make_Set()、Find_Set()、Union_Set()。 rank[a]的改变是伴随着father[a]的改变而更新的 17 (有father改变就有rank改变),要是father改变了,而rank未改变,此时的rank就记录了一个错误的值,father未改变 18 (即使实际的father已不是现在的值,但只要father未改变,rank 的值就是“正确”的,认识到这点很重要。) 19 */ 20 21 #include<stdio.h> 22 int father[100005],rank[100005]; 23 24 int find(int a) 25 { 26 int t; 27 if(father[a]==a) 28 return a; 29 30 t=father[a]; 31 father[a]=find(father[a]); 32 rank[a]=(rank[a]+rank[t]+1)%2;//必须有,更新路径压缩之后a与根结点之间的关系; father改变,rank就必须要跟着改变 33 34 return father[a]; 35 } 36 37 void merge(int a,int b) 38 { 39 int fa,fb; 40 fa=find(a); 41 fb=find(b); 42 if(fa!=fb) 43 { 44 father[fa]=fb; 45 rank[fa]=(rank[a]+rank[b])%2;//fa结点以下的结点的rank不需要改,因为在find中会自动更新 46 } 47 } 48 49 int main() 50 { 51 int T,a,b,m,n,i; 52 char cmd[2]; 53 scanf("%d",&T); 54 while(T--) 55 { 56 scanf("%d%d",&n,&m); 57 for(i=1;i<=n;++i) 58 { 59 father[i]=i; 60 rank[i]=1; 61 } 62 for(i=0;i<m;++i) 63 { 64 scanf("%s%d%d",cmd,&a,&b); 65 if(cmd[0]=='A') 66 { 67 if(find(a)==find(b)) 68 { 69 //在使用rank之前,已经在用find函数寻找a的时候将a路径上的所有结点的rank值改变过了 70 if((rank[a]+rank[b])%2==0) //a和b与根节点的关系相同---都是0后者都是1,说明是同一个帮派 71 printf("In the same gang.\n"); 72 else 73 printf("In different gangs.\n"); 74 } 75 else 76 printf("Not sure yet.\n"); 77 } 78 else 79 merge(a,b); 80 } 81 } 82 return 0; 83 }
代码二:
1 //重新做了一遍,又理了理思路 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 6 int father[100005],relation[100005]; 7 8 void init(int n); 9 int find(int x); 10 11 int main() 12 { 13 int T,N,M,x,y,fx,fy,r1,r2; 14 char w[3]; 15 scanf("%d", &T); 16 while(T--) 17 { 18 scanf("%d%d", &N, &M); 19 init(N); 20 while(M--) 21 { 22 scanf("%s%d%d", w, &x, &y); 23 fx=find(x); 24 fy=find(y); 25 if(w[0]=='D') 26 { 27 if(fx != fy) 28 { 29 father[fx]=fy; 30 //相当于已知 a 与 b 的关系(relation[x]),已知 c与 d 的关系(relation[y]),已知 b 与 c 的关系(1),求 a 与 d 的关系 31 relation[fx]=(relation[x]+relation[y]+1)%2; 32 } 33 } 34 else 35 { 36 if(fx!=fy) 37 printf("Not sure yet.\n"); 38 else 39 { 40 if(relation[x]!=relation[y]) 41 printf("In different gangs.\n"); 42 else 43 printf("In the same gang.\n"); 44 } 45 } 46 } 47 } 48 return 0; 49 } 50 void init(int n) 51 { 52 int i; 53 for(i=0;i<=n;++i) 54 { 55 father[i]=i; 56 relation[i]=0; 57 } 58 } 59 int find(int x) 60 { 61 if(x==father[x]) 62 { 63 return x; 64 } 65 else 66 { 67 int t=father[x]; 68 father[x]=find(father[x]); 69 70 //相当于已知 a 与 b 的关系,已知 b 与 c 的关系,求 a 与 c 的关系 71 relation[x]=(relation[x]+relation[t])%2;//(注意顺序,只有当前节点的父亲节点与根节点的关系确定了才能正确确定) 72 return father[x]; //当前节点与根节点的关系所以这条语句一定不能放在上一条语句的上边 73 } 74 }