【数据结构】并查集之二

来源:互联网 发布:php sendmail centos 编辑:程序博客网 时间:2024/06/07 22:03

1. 两类类别


并查集中有两类类别,即并查集中元素要么属于集合A,要么属于B,且A与B不相交。

利用向量得到关系:



1.1 POJ 2492


源代码:

#include "stdio.h"int parent[2000],relation[2000];int find(int x)   {int root,tail,temp;if(parent[x]==x)return x;    else{for(root=x;parent[root]!=root;root=parent[root]);for(tail=x;tail!=root;){temp=parent[tail];parent[tail]=root;tail=temp;}return root;}}void update(int yroot,int n){int i;for(i=1;i<=n;i++){if(i!=yroot&&find(i)==yroot)relation[i]=(relation[i]+relation[yroot])%2;}}void root_union(int x,int y,int xroot,int yroot,int n){relation[yroot]=(relation[x]-relation[y]+1)%2;update(yroot,n);parent[yroot]=xroot;}int main(){int scena_num,bug_num,intera_num,a,b,i,count;int aroot,broot,suspi_flag;    scanf("%d",&scena_num);for(count=1;count<=scena_num;count++){scanf("%d%d",&bug_num,&intera_num);suspi_flag=0;for(i=1;i<=bug_num;i++){parent[i]=i;relation[i]=0;}while(intera_num--){scanf("%d%d",&a,&b);aroot=find(a);broot=find(b);if(aroot!=broot){root_union(a,b,aroot,broot,bug_num);}else{if(relation[a]!=(relation[b]+1)%2)   suspi_flag=1;}}if(suspi_flag==1)printf("Scenario #%d:\nSuspicious bugs found!\n\n",count);elseprintf("Scenario #%d:\nNo suspicious bugs found!\n\n",count);}return 0;}

1.2 POJ 1703


源代码:

#include "stdio.h"int parent[100000],relation[100000];int find(int x)   //寻找root结点,并更新parent链域的relation值{int temp;if(parent[x]==x)return x;    temp=parent[x];parent[x]=find(parent[x]);relation[x]=(relation[x]+relation[temp])%2;       return parent[x];}int main(){int T,N,M,i,a,b;int aroot,broot;char message;    scanf("%d",&T);while(T--){scanf("%d%d",&N,&M);for(i=1;i<=N;i++){parent[i]=i;relation[i]=0;}while(M--){getchar();scanf("%c%d%d",&message,&a,&b);aroot=find(a);broot=find(b);if(message=='A'){if(N==2&&a!=b)printf("In different gangs.\n");else{if(aroot==broot){if(relation[a]==relation[b])printf("In the same gang.\n");elseprintf("In different gangs.\n");}elseprintf("Not sure yet.\n");}}else{if(aroot!=broot){parent[broot]=aroot;relation[broot]=(relation[a]-relation[b]+1)%2;}}}}return 0;}


2. 三类类别


并查集中元素属于互不相交的集合A, B, C。


类似地,可以得到如下关系:

r[y]=(r[x]+d)%3                       //不能得到r[x]=(r[y]+d)%3   

r[yroot]=(r[x]-r[y]+d+3)%3      //+3,是因为r[x]-r[y]+d有可能为负数

其中,0表示与root节点同类,1表示吃root节点,2表示被root节点吃。


2.1 POJ 1182


源代码:

#include "stdio.h"int parent[50000],relation[50000];int find(int x)   {int temp;if(parent[x]==x)return x;    temp=parent[x];parent[x]=find(parent[x]);relation[x]=(relation[x]+relation[temp])%3;       return parent[x];}int main(){int num_ani,num_sta,i,statement,count=0;int a,b,aroot,broot,d;    scanf("%d%d",&num_ani,&num_sta);for(i=1;i<=num_ani;i++){parent[i]=i;relation[i]=0;}while(num_sta--){getchar();scanf("%d%d%d",&statement,&a,&b);d=statement-1;        if(a>num_ani||b>num_ani)count++;else{aroot=find(a);broot=find(b);if(aroot!=broot){parent[broot]=aroot;relation[broot]=(relation[a]-relation[b]+d+3)%3;}else if(relation[b]!=(relation[a]+d)%3||(d==1&&a==b))count++;}}printf("%d\n",count);return 0;}