【转】
解析:并查集的题目,并查集的拓展。一般的思路是先初始化,各个数自成一个组,然后是两个gangs自成一个组,但由于两个给定元素有三种关系:
In the same gang;
In different gangs;
Not sure yet; 采用此模型的缺点是判断两个元素关系还未确定这种情况比较复杂,故模型需要改进。本题的正确模型是将已经确定关系的元素组成一个集合,然后利用两个元素的 father是同一个来确定这两个元素之间的关系。father[a]中存放的是a的根结点,rank中存放的是father[a]与a的关系,0表示两 者不在同一个gangs中,1表示两者在同一个gangs中。具体的程序还是沿袭了并查集的Make_Set()、Find_Set()、 Union_Set()的三步骤。
心得:并查集有三步是必须的:
Make_Set()、Find_Set()、Union_Set()。
rank[a]的改变是伴随着father[a]的改变而更新的(有father改变就有rank改变)
,要是father改变了,而rank未改变,此时的rank就记录了一个错误的值,father未改变(即使实际的father已不是现在的值,但只要father未改变,rank 的值就是“正确”的,认识到这点很重要。),第一次错误就是因为没有考虑清楚这点。
#include <iostream>
#include <cstdio>
using namespace std;
const int SIZE = 100002;
typedef struct node
{
int parent;
int relation;
}node;
int n, m;
node p[SIZE];
void init()
{
for(int i=1;i<=n;i++)
{
p[i].parent=i;
p[i].relation=1; //0父子不同类,1父子同类
}
}
int find(int x)
{
if(x==p[x].parent)
return x;
int temp=p[x].parent; //记录下x的父亲节点
p[x].parent=find(p[x].parent); //压缩x的父亲节点
p[x].relation=(p[temp].relation+p[x].relation+1)%2; //已知了x的父亲节点与根的关系,求x与根的关系的表达式
return p[x].parent;
}
void union_set(int x, int y)
{
int px, py;
px=find(x);
py=find(y);
if(px==py) return;
p[py].parent=px;
p[py].relation=(p[x].relation+p[y].relation)%2;
}
int main()
{
int T;
char ch;
int x, y;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
init();
for(int i=0;i<m;i++)
{
getchar();
scanf("%c %d %d",&ch,&x,&y);
if(ch=='D')
{
union_set(x,y);
}
else if(ch=='A')
{
if(find(x)==find(y)) //已经在用Find函数寻找x的时候将x路径上的所有结点的relation值改变过了
{
if(p[x].relation==p[y].relation) printf("In the same gang.\n");
else printf("In different gangs.\n");
}
else
printf("Not sure yet.\n");
}
}
}
return 0;
}
/******
1
4 5
D 1 2
D 1 3
A 2 3
D 2 3
A 2 3
******/
总结:此题的思路基本和POJ 1182类似。