题目链接:http://poj.org/problem?id=2492
题目描述:有种虫子只有雌雄两种性别,给出若干条虫子之间的交配记录。看其中是否有奇怪的事情发生、、、、= =
解题思路:第一次做这种题,不太会做。参考了http://blog.csdn.net/freezhanacmore/article/details/8799495这位的博客。用并查集解决, r 数组中存 0 代表与父节点同性,存 1 代表与父节点异性,find过程中要不断更新。merge过程中注意改变根节点的性别(详见代码)。只有彻底理解并查集的结构和原理才能解决这类问题,其中 find 和 union 函数中的那个公式我还是没理解太透彻。。需要再做一些题。。= =
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int arr[3000],r[3000];
int ans;
void reset()
{
ans=0;
memset(r,0,sizeof(r));
for(int i=0;i<3000;i++)
arr[i]=i;
}
int find_father(int x)
{
if(arr[x]==x)
return x;
int t=arr[x];
arr[x]=find_father(arr[x]);
r[x]=(r[t]+r[x])%2; //与父节点同性记作0,异性记作1。
return arr[x];
}
void Union(int a,int b)
{
int fa=find_father(a);
int fb=find_father(b);
arr[fa]=fb;
r[fa]=(r[a]+r[b]+1)%2; //这句话我没理解透呢。。日后再说
}
int main()
{
int T,i,a,b,K,N;
scanf("%d",&T);
for(i=1;i<=T;i++)
{
reset();
scanf("%d%d",&N,&K);
while(K--)
{
scanf("%d%d",&a,&b);
//cout<<r[1]<<" "<<r[2]<<" "<<r[3]<<endl;
if(!ans)
{
if(find_father(a)==find_father(b)) //※注意,这句判断会改变 r 数组中的值!!必须放前面。
{
//cout<<r[1]<<" "<<r[2]<<" "<<r[3]<<" hehe"<<endl;
if(r[a]==r[b])
ans=1;
continue; //两条虫已经是一个集合里并且相对于根节点的性别还相同(即性别相同),发现同性恋了!
}
else
Union(a,b); //两条虫还不属于一个集合里,可以交配。
}
//cout<<r[1]<<" "<<r[2]<<" "<<r[3]<<endl;
}
printf("Scenario #%d:\n",i);
if(ans)
printf("Suspicious bugs found!\n");
else
printf("No suspicious bugs found!\n");
if(i!=T)
printf("\n");
}
return 0;
}
AC截图: