您的位置:首页 > 其它

POJ 1703 Find them, Catch them(并查集)

2010-07-23 17:07 309 查看
//并查集,NND忘了个句号WA了3次!
//A过POJ1182的食物链后再来做这道题就轻松多了,这是食物链的简单版
//并查集的集合是以能否确定关系来分的,而不是以属于同一个帮派或不同帮派来分的
//这类题只需建立一个并查集,然后维护每个结点和他的根结点之间的关系属性即可
//如果2个点不在同一个并查集中,那么这2个点无法确定关系
//在同一个并查集中的每个点,都能确定集合中的相互关系
#include<iostream>
using namespace std;
struct node
{
int fa;
int rank;//rank = 0表示当前结点和他父亲是相同的黑帮,=1表示不同黑帮
}set[100005];
int n,m,x,y,fa_x,fa_y;
void init()
{
for(int i = 1;i <= n;++i)
{
set[i].fa = i;
set[i].rank = 0;//初始化全部都是相同的,比较好递推
}
}
int Find(int x)
{
int temp = set[x].fa;//先将当前X的父亲保存下来
if(x == set[x].fa)	return x;
set[x].fa = Find(temp);//递归找父亲顺便路径压缩,这时候set[x].fa存放的就是这颗树的根了
set[x].rank = (set[temp].rank + set[x].rank) % 2;//通过这条递推式在路径压缩的时候更新状态
return set[x].fa;//返回跟
}
void Union(int x,int y,int fa_x,int fa_y)
{
set[fa_x].fa = fa_y;
set[fa_x].rank = (set[x].rank + set[y].rank + 1) % 2;//通过x和y的rank关系来更新x根结点的rank
}
int main()
{
//freopen("in.txt","r",stdin);
int t;
char cmd;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
while(m--)
{
scanf("/n%c",&cmd);
if(cmd == 'A')
{
scanf("%d%d",&x,&y);
fa_x = Find(x);
fa_y = Find(y);
if(fa_x != fa_y)	printf("Not sure yet./n");//当前的两个结点如果不在同一颗树上,就无法判定他们是否属相同帮派
else
{
if(set[x].rank != set[y].rank)
printf("In different gangs./n");
else
printf("In the same gang./n");
}
}
else
{
scanf("%d%d",&x,&y);
fa_x = Find(x);
fa_y = Find(y);
Union(x,y,fa_x,fa_y);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: