唉,这道题更是让我花费了不少时间,好多大牛都说很简单,但是…………
很无语就对了,一下部分接受转自http://www.cppblog.com/abilitytao/archive/2010/05/14/98899.html
大牛虽然解释了好多,但综合了很多的博客里面的介绍之后,我终于有了些许的感悟,我想,结合我在程序中的注释应该会容易理解一点
大牛的介绍:
题目的大意是给出n只bug和m次观察到的性行为,并以此为依据判断两只bugs是不是有同性恋行为(gay)。
比如3只bug
1 2有性行为
2 3有性行为
1 3有性行为
---->>>>>首先1,2是异性。
---->>>>>然后2,3是异性。
可以推出1,3是异性。
但是1,3有性行为,所以可以判断出有一定有同性恋。
剥离这个题目所赋予的外壳,我们抽出这个问题的本质:并查集!
其实,这里最重要的是去维护每一个点到集合顶点的偏移量。(注意:下面生造了一个词 所谓集合元素 比如说f[i]=i,那么i就是集合元素,集合偏移量就是集合元素的偏移量)
初始状态下,应该是
i号点挂在i号集合下面
我们考虑一般情况:假设合并的过程已经进行了一部分 ,这样每一个集合下面都有元素,且各自对于顶点的偏移量都算出来了;
现在在a集合中的元素x和b集合中的元素y进行合并。此时有两中情况改变偏移量;
1.首先是集合的合并,如果要将a,b集合合并,又要保证x,y数字的kind不相同,比如说把b集合挂到a集合下面去。
代表集合的那个元素,他的偏移量永远是0,所以b要改变偏移量,使得b里面的y在进行变换后要和x相异。
如果 kind[x]=0;kind[y]=0;那么y对应的那个代表集合的元素的偏移量必须变成1,因为只有这样才能使得合并后,x,y有不同的kind;
如果 kind[x]=0,kind[y]=1;y对应代表集合的元素偏移量是0,所以对应集合偏移量还是0;
类推 kind[x]=1,kind[y]=0,同上,0;
kind[x]=1,kind[y]=1,y集合偏移量应该变为1;
综上 可以得到一个同或的关系。
用等式 kind[a]=(kind[x]+kind[y]+1)%2;恰好满足要求.
2.然后是压缩路径时候的偏移量改变
个人认为,这个主要是解决集合合并时候产生的“残余问题”,因为在合并集合的时候只是考虑了集合的偏移量,至于它下面的元素一概不管。一个压缩路径既分离了父子元素的偏移量,又使得子元素直接指向集合元素。
#include<stdio.h> #define MAXN 2010 int f[MAXN],kind[MAXN],n; int find(int x) { if(x==f[x]) return x; int t=find(f[x]); kind[x]=(kind[x]+kind[f[x]])%2; //Union函数中仅对集合的偏移量做出了修改,并未对集合中元素的偏移量修改,注意里面的递归调用,可以发现: //括号中的kind[x]表示的是与父节点的关系,等式左边的那个表示与跟节点的关系,而kind[f[x]]表示的是与根节点的关系 //所以根据kind[x]和kind[f[x]]则可以推出x与根节点的关系 f[x]=t; return f[x]; } int Union(int x,int y) { int a=find(x); int b=find(y); if(a==b)//表明x与y已经建立了联系 { if(kind[x]==kind[y]) return 1;//表示有同性恋 } else{ f[a]=b;//将x所在的a集合并入y所在的b集合 kind[a]=(kind[x]+kind[y]+1)%2;//这里研究了好久,x跟a的关系确定,y跟b的关系确定,从而推出a跟b的关系 } return 0; } int main() { int m,i,j=0,flag,t,a,b; scanf("%d",&t); while(t--) { flag=0; scanf("%d %d",&n,&m); for(i=1;i<=n;i++) { f[i]=i; kind[i]=0; } for(i=1;i<=m;i++) { scanf("%d %d",&a,&b); if(Union(a,b)) flag=1; } if(flag==1) printf("Scenario #%d:\nSuspicious bugs found!\n\n",++j); else printf("Scenario #%d:\nNo suspicious bugs found!\n\n",++j); } return 0; }
总而言之,并查集的操作就是不断地维护者各个集合中,每个元素身上对集合元素的偏移关系。从而确定他们是否具有同性恋。
在这个题中,假设是不存在同性恋的,所以只有找到矛盾才输出 有同性恋。