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);
else
printf("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");
else
printf("In different gangs.\n");
}
else
printf("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;
}