您的位置:首页 > 其它

POJ 1703 Find them, Catch them(并查集的拓展)

2016-11-26 15:57 555 查看
题目链接http://poj.org/problem?id=1703

题目大意:给定n,m,n表示罪犯的总数,m表示下面有m次操作,每次操作A (x,y)表示询问x,y是否属于同一伙,D(x,y)表示x,y确定为同一伙。输出每次询问对应的结果。

解题思路:每个罪犯要么属于0集合,要么属于1集合,对应的就是二分图的染色问题,我们可以用并查集表示其中的关系,中间用数组标记处理每个罪犯属于哪个集合。

重点是如何标记?a[x]=(a[x]+a[fa])%2即x结点的值是由当前的值和它的父亲结点所决定的,当要合并两个拥有不同父亲结点的子节点时,我们可以先判断这两个节点原本是否属于相同集合,如果是相同集合,则要更新其中一个父亲结点的值变成另一个集合(这一点要好好理解),否则没有影响,不用更新。

AC代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
#include<map>
#include<vector>
using namespace std;
#define mann 100005
#define INF 0x3f3f3f3f
int set[mann];
int vis[mann];
int aa[mann];
int find(int v)
{
if(set[v]==v)
return v;
int u=set[v];
set[v]=find(set[v]);
aa[v]=(aa[v]+aa[u])%2;
return set[v];
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
set[fy]=fx;
if(aa[x]==aa[y])//x,y在相同集合,更新y的父亲结点的值
aa[fy]=!aa[fy];
}
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
int a,b;
char s[10];
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
set[i]=i;
vis[i]=0;
aa[i]=0;
}
for(int i=1; i<=m; i++)
{
scanf("%s%d%d",s,&a,&b);
if(s[0]=='A')
{
if(find(a)==find(b))
{
if(aa[a]==aa[b])
printf("In the same gang.\n");
else
printf("In different gangs.\n");
}
else
printf("Not sure yet.\n");
}
else
merge(a,b);
}
}
}


做题时要好好理解,掌握精髓之后下次做题才会AC。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: