ACM并查集浅谈

并查集,顾名思义,就是查找集合然后合并。主要思想就是通过find-union函数实现的,所有的元素都用一个数组表示。如果两个元素属于一个集合,就用find函数将两个元素划分到一个集合中。属于同一集合的元素构成一棵树,如果两个元素的根相同,则属于同一集合。


在ACM常见题中,主要分为两种情况:

1.集合数量未知。

2.集合数量已知。

对于集合数量未知的情况,根据题意修改一下find-union函数,然后将两个元素(或者别的什么,根据题意)划分到一个集合中即可。

对于集合数量已知的情况,需要将元素分到特定的集合中,表示方法也不是像上种情况那样,这也是本文重点要讲解的。


这类题根据题意,了解要分为多少个集合,然后将确定关系的元素划分到一个集合中,如果两者根不同,则二者还没有确定关系。如果二者根相同,则二者有关系,但关系不确定。这里可以用一个公式来区分二者的关系:

rela[x] = (rela[x] + rela[uf[x]) % MOD;

uf[]是记录x的父亲节点的,rela[]是记录x与其父亲的关系的,MOD是划分集合的数量。

每个元素都记录与其父亲的关系,在整个树上就能判断任意两者的关系了。

当两者确定关系后,将两个元素连到一个树里,要用到另一个公式:

rela[px] = (rela[y] - rela[x] + MOD) % MOD;

px是x的根节点。


关于第二个公式的推导:

fx->fy = fx->x + x->y + y->fy;

这里用到了向量的思想,分解了路径,从而求出未知的路径。

下面是find-union函数的模板。

//find函数</span>
 uf_find(int x)
{
	if (uf[x] == x)
		return x;
	int tmp = uf[x];
	uf[x] = uf_find(tmp);
	sign[x] = (sign[tmp] + sign[x]) % MOD;
	return uf[x];
}

//union函数
void uf_union(int a, int b, int pa, int pb)
{
	uf[pa] = pb;
	sign[pa] = (sign[b] - sign[a]) % MOD;
}



如何判断两个元素的关系judge函数:

根据rela[]可以判断x与其父亲的关系,从x一直加到根,然后modMOD,就可以得出x与根的关系,y也如此,然后就可以通过判断x和y的值判断二者的关系了。


下面是judge函数的实现:

//judge函数
void uf_judge(int n)
{
	int x, tmp;
	for (int i = 1; i <= n; i++)
	{
		x = i;
		while (x != uf[x])
		{
			tmp = uf[x];
			judge[i] = (sign[x] + judge[i]) % MOD;
			x = tmp;
		}

	}
}


注:

由于判断两者关系的机制博主没看太懂,从而写了这个judge函数,对于两个集合的情况已经验证过了,其他情况还没有证实过,但估计应该没错。

还有,find-union函数还可以继续优化,比如union的按秩合并,但是这种启发式的优化不明显,所以这里不介绍了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值