参考 http://blog.csdn.net/dm_vincent/article/details/7655764
动态连通图可能的操作
查询节点属于的组:数组对应位置的值即为组号
判断两个节点是否属于同一组:分别得到两个节点的组号,然后判断组号是否相等
连接两个节点:分别得到两个节点的组号,组号相同时,退出操作,组号不同时,通过判断组大小进程连接
获取组的数目:初始化为整个数组的大小,每次连接后,递减一
class UF;
Union(int i,int j); 连接
int Find(int i); 查找组号
BOOL Cnnected(int i,int j) 判断是否为同一组
int Count(); 返回组号
class UF
{
private :
int* id;
int count;
public:
int* sz;
UF(int N)
{
count = N;
id = new int[N];
sz = new int[N];
for (int i = 0; i < N; i++)
{
id[i] = i;
sz[i] = 1;
}
}
int Find(int i) //路径压缩
{
while (i != id[i])
{
id[i] = id[id[i]]; //将父节点设置为爷爷节点
i = id[i];
}
return i;
}
int Count()
{
return count;
}
BOOL Connected(int i, int j)
{
return Find(i) == Find(j);
}
VOID Union(int i, int j)
{
int a;
int b;
a = Find(i);
b = Find(j);
if (Find(i) == Find(j))
{
return;
}
if (sz[i] < sz[j]) //比重
{
id[a] = b;
}
else
{
id[b] = a;
}
count--;
}
};
int main()
{
UF uf(10);
int i;
int j;
int V1[6][2] = { 1,2,4,5,7,6,3,9,7,2,3,2 };
for (i = 0; i < 6; i++)
{
uf.Union(V1[i][0], V1[i][1]);
}
j = uf.Count();
printf("组号 %d", j);
return 0;
}
-----------------------------------------------------------------------------------------------
poj上一个题目 个人解题的思路 也有借鉴
A吃B B吃C C吃A 总共树林里有三种动物,N个动物 现在有一定数量的话 要求判断真假 并输出假话个数
解题思路:
不同于普通的并查集,这个题目节点直接存在一定的利害关系,故考虑这是一个带权并查集,即确定每个节点所带的数值来表示其与父节点或子节点的关系。
一,确定权值(这里应该是相对于子节点)
现在定义如下
取 0 1 2 来表示关系,原因:第一 父节点和子节点关系有三种——同类 相对于子节点(被父节点吃 和吃父节点) 相对于父节点(吃子节点和被子节点吃) 第二 题意所需 在后续会明白
0 表示父节点和子节点同类
1 表示子节点被父节点吃或父节点吃子节点
2 表示子节点吃父节点或父节点被子节点吃
二,初始化
对每个节点进行初始化
节点结构
struct animal{
int relation;
int parents;}
在初始化时每个节点按序赋值 ,relation为1(自己与自己是同类),parents=id(自己)
压缩路径
在每一次查询的过程中,将子节点连接到爷爷节点上
animal[i].parents = animal[animal[i].parents].parents;
这里就出现了这个问题的核心 在压缩路径后,由于破坏了原有的状态,如何根据原有的信息,来得到新的信息。
即如何确定子节点和爷爷节点的relation
这里采用枚举法观察
子节点 父节点 子节点和爷爷节点的关系
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
2 0 2
2 1 0
2 2 1
不难发现 这里子节点和爷爷节点的关系可写为
r[子爷] = (r[子] + r[父])%3
现在处理稍复杂情况连接
x->y->p x->q 现在将两个进行合并 即将两个根节点相连
这里处理方法为
1. 通过x->q推出 q相对于x的关系
这里通过枚举
子节点 父相对于子
0 0
1 2
2 1
规律为 r[父相对于子] = (3- r[子])%3
现在过程为
2.x->y->p 在通过x找根节点时 将x连接到p上
这里 r[x1] = (r[x]+r[y])%3
对于x->q
r[q相对于x] = (3-r[x])%3
现在等价为q->x->p 将q连接到p上
r[q] =(r[x1] + r[q])
= (r[x] + r[y] + (3-r[x])%3 )%3
Union函数
最为复杂 这里情况多变但由于存在路径压缩 所以知树的高度一般最多不会超过三层。故最长只会出现
x1->x2->x3 与y1->y2->y3 进行连接 这应该是最复杂的情况
首先在处理时确定一个前提 那就是 只有从y到x的连接 就是每句话的后一个向前一个进行连接
现在是最简单的
situaion 1:
1 x1 y1 (x1 and y1 are all the roots at this situation)
solution:
Find(x1)
change relaion(x1)
Find(y1)
change relaion(y1) //nothing happen
y1.parent = x1
y1.relation = 1-1
situation 2:
2 x1 y1 (x1 and y1 are all the roots at this situation)
solution:
Find(x1)
change relaion(x1)
Find(y1)
change relaion(y1) //nothing happen
y1.parent = x1
y1.relation = 2-1
situation 3:
1 x2 y1(x2->x1 y1 is the root)
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y1)
change relaion(y1)
y1.parent = x2
y1.relation = 1-1
situation 4:
2 x2 y1((x2->x1 y1 is the root)
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y1)
change relaion(y1)
yroot.parent = x2
yroot.relation = 2-1
situation 5:
1 x2 y2((x2->x1 y2->y1 )
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y2) //yroot = y1
change relaion(y2)
yroot.parent = xroot
yroot.relation = ((3-r[yroot])%3 + d - 1(话中的数) + r[x2])%3
而对于更加复杂的情况 可用上述式子进行等效替换 故不进行赘述。
这里是大致思想
代码就不进行粘贴