FIND函数要用到路径压缩的原因是在根节点的一颗子树上,沿着这颗子树的所有子节点都与他的父亲节点互为异性,所以可以直接看成字数上的所有子节点都与祖先节点互为异性。所以用路径压缩。
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
using namespace std;
#define L(x) x<<1
#define R(x) x<<1|1
#define pi actan(-1.0)//常规,误删
#define mem(x,y) memset(x,y,sizeof(x))
#define per(i,n) for(int i=1;i<=n;++i)
#define rep(i,n) for(int i=n;i>=1;--i)
const int max_=2000+10;//更改+10之前的
int pra[max_],n,m,a,b,flag,rank[max_];
void init()
{
per(i,n) pra[i]=i;
}
int find(int x)
{
int tmp,son;
son=x;
while(x!=pra[x])//还没有找到根节点
x=pra[x];//把当前节点改为他的上级
while(son!=x)//路径压缩
{
rank[son]=(rank[son]+rank[pra[son]])%2;
tmp=pra[son];
pra[son]=x;
son=tmp;
}
return x;//当前的节点已经是根节点了,于是,返回查询节点的根节点,整个过程不改变树的结构,只负责查询
}
int join(int b1,int b2)//两颗树的合并操作
{
int x=find(b1);//找到树b1的根节点
int y=find(b2);//找到树b2的根节点
if(x==y)
{
if((rank[b1]+rank[b2])%2==0)
return 1;
else return 0;
}
else
{
pra[y]=x;
rank[y]=(rank[b1]+rank[b2]+1)%2;
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
per(i,t)
{
flag=0;//没有同性恋
mem(rank,0);
scanf("%d%d",&n,&m);
init();
per(j,m)
{
scanf("%d%d",&a,&b);
if(join(a,b))
flag=1;
}
printf("Scenario #%d:\n",i);
if(flag==0)
printf("No suspicious bugs found!\n");
else
printf("Suspicious bugs found!\n");
if(i<t)
printf("\n");
}
return 0;
}
本体采用了路径压缩,便于处理rank,是子节点与祖先接待你直接相连,然后从底向上更改rank,这样就只有两层的深度(估计的),之后,只要比较同一层次有没有连接的情况,就可以判断是否矛盾,