Time Limit: 10000MS | Memory Limit: 65536K | |
Total Submissions: 21637 | Accepted: 7056 |
Description
Input
Output
Sample Input
2 3 3 1 2 2 3 1 3 4 2 1 2 3 4
Sample Output
Scenario #1: Suspicious bugs found! Scenario #2: No suspicious bugs found!
1 /* 功能Function Description: POJ-2492 并查集应用的扩展 2 开发环境Environment: DEV C++ 4.9.9.1 3 技术特点Technique: 4 版本Version: 5 作者Author: 可笑痴狂 6 日期Date: 20120808 7 备注Notes: 8 关于并查集,注意两个概念:按秩合并、路径压缩。 9 1、按秩合并 10 由于并查集一般是用比较高效的树形结构来表示的,按秩合并的目的就是防止产生退化的树(也就是类似链表的树), 11 用一个数组记录各个元素的高度(也有的记录各个元素的孩子的数目,具体看哪种能给解题带来方便), 12 然后在合并的时候把高度小的嫁接到高度大的上面,从而防止产生退化的树。 13 2、路径压缩 14 而另一个数组记录各个元素的祖先,这样就防止一步步地递归查找父亲从而损失的时间。因为并查集只要搞清楚各个元素所在的集合, 15 而区分不同的集合我们用的是代表元素(也就是树根),所以对于每个元素我们只需保存其祖先,从而区分不同的集合。 16 而我们这道题并没有使用纯正的并查集算法,而是对其进行了扩展, 17 我们并没有使用“1、按秩合并”(当然你可以用,那样就需要再开一个数组) 18 我们从“1、按秩合并”得到启示,保存“秩”的数组保存的是 元素相对于父节点的关系 ,我们岂不可以利用这种关系 19 (即相对于父节点的不同秩值来区分不同的集合),从而可以把两个集合合并成一个集合。 20 (注:此代码 relation=0 代表 和父节点同一性别) 21 */ 22 23 24 #include<stdio.h> 25 int father[2005]; 26 int relation[2005]; 27 28 int find_father(int i) 29 { 30 int t; 31 if(father[i]==i) 32 return i; 33 34 //计算相对于新的父节点(即根)的秩,relation[t]是老的父节点相对于新的父节点(即根)的秩,relation[i]是i元素相对于老的父节点的秩, 35 //类似于物理里的相对运动,得到的r[i]就是相对于新的父节点(即根)的秩。而且这个递归调用不会超过两层 36 t=father[i]; 37 father[i]=find_father(father[i]); 38 relation[i]=(relation[i]+relation[t]+1)%2; //注意递归中把这棵树relation中的的值都更新一遍,这句的顺序 不能 和上一句 调换位置 39 // relation[a]的改变是伴随着father[a]的改变而更新的(有father改变就有relation改变),要是father改变了,而relation未改变,此时的relation就记录了一个错误的值, 40 //father未改变(即使实际的father已不是现在的值,但只要father未改变,relation的值就是“正确”的,认识到这点很重要。) 41 return father[i]; 42 } 43 44 void merge(int a,int b) 45 { 46 int x,y; 47 x=find_father(a); 48 y=find_father(b); 49 father[x]=y; 50 relation[x]=(relation[b]-relation[a])%2;//relation[a]+relation[x]与relation[b]相对于新的父节点必须相差1个等级,因为他们不是gay 51 } //x下边的节点不用改,因为查找的时候会自动更新 52 53 int main() 54 { 55 int T,m,n,i,j,a,b,flag; 56 scanf("%d",&T); 57 for(i=1;i<=T;++i) 58 { 59 flag=0; 60 scanf("%d%d",&n,&m); 61 for(j=1;j<=n;++j) //初始化 62 { 63 father[j]=j; 64 relation[j]=1; 65 } 66 for(j=1;j<=m;++j) 67 { 68 scanf("%d%d",&a,&b); 69 if(find_father(a)==find_father(b)) 70 { 71 // if(relation[a]!=(relation[b]+1)%2) 72 if(relation[a]==relation[b]) //说明是同性 73 flag=1; 74 } 75 else 76 merge(a,b); 77 } 78 if(flag) 79 printf("Scenario #%d:\nSuspicious bugs found!\n\n",i); 80 else 81 printf("Scenario #%d:\nNo suspicious bugs found!\n\n",i); 82 } 83 return 0; 84 }
复习并查集,又重新做了一遍:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 5 using namespace std; 6 7 const int MAX = 2005; 8 9 bool flag; 10 int fa, fb, n; 11 int father[MAX], rela[MAX]; 12 13 int find(int x) 14 { 15 if(father[x] == -1) 16 return x; 17 else 18 { 19 int tmp = father[x]; 20 father[x] = find(father[x]); 21 22 rela[x] = (rela[x]+rela[tmp])%2; 23 return father[x]; 24 } 25 } 26 27 int main() 28 { 29 int T, m, a, b; 30 scanf("%d", &T); 31 for(int k = 1; k <= T; ++k) 32 { 33 flag = true; 34 scanf("%d%d", &n, &m); 35 { 36 memset(father, -1, (n+1)*sizeof(int)); 37 memset(rela, 0, (n+1)*sizeof(int)); 38 while(m--) 39 { 40 scanf("%d%d", &a, &b); 41 if(!flag) 42 continue; 43 fa = find(a); 44 fb = find(b); 45 46 if(fa != fb) 47 { 48 father[fa] = fb; 49 rela[fa] = (rela[a] + rela[b] + 1)%2; 50 } 51 else 52 { 53 if(rela[a] == rela[b]) 54 flag = false; 55 } 56 57 } 58 59 printf("Scenario #%d:\n", k); 60 if(flag) 61 printf("No suspicious bugs found!\n\n"); 62 else 63 printf("Suspicious bugs found!\n\n"); 64 } 65 } 66 return 0; 67 }