第7周博客,并查集笔记

目录

并查集 (Disjoint-set)

Step 1:

 Step2: 

Step 3: 

 Step 4:

避免最坏情况:

 继续优化:

I - Namesolo 拜师

一:维护生成树

二:按秩合并

证明:

三:路径压缩


并查集 (Disjoint-set)

每个集合用一棵“有根树”表示 定义数组 set[1…n] set[i] = i, 则i表示本集合,且是集合对应树的根 set[i] = j,j<>i, 则 j 是 i 的父节点.

int findSet(int x)
{
	if (x == set[x])
		return x;
	else
		return findSet(set[x]);
}
void unionSet(int x, int y)
{
	int fx = findSet(x);
	int fy = findSet(y);
	set[fy] = fx;
}

Step 1: nobody is anybody friend. We have 5 trees and each tree has a single element, which is the root and the representative of that tree.

i

1

2

3

4

5

set[i]

1

2

3

4

5

 Step2: 1 and 2 are friends, unionSet(1, 2) Then we have 4 trees one tree contain 2 elements and have the root 1. The other trees have a single element.

 

i

1

2

3

4

5

set[i]

1

1

3

4

5

Step 3: 5 and 4 are friends, unionSet(5, 4) Now we have 3 trees, 2 trees with 2 elements and one tree with one element.

i

1

2

3

4

5

set[i]

1

1

3

5

5

 Step 4: 5 and 1 are friends, unionSet(1, 5) Now we have 2 trees, one tree has 4 elements and the other one has only one element.

i

1

2

3

4

5

set[i]

1

1

3

5

1

算法复杂度: findSet(x) 最坏O(n) unionSet(x, y) 最坏O(n) 

最坏:

 

避免最坏情况:

启发式合并 方法:将深度小的树合并到深度大的树 实现:假设两棵树的深度分别为h1和h2, 则合并后的树的高度h是: max(h1,h2), if h1<>h2. h1+1, if h1=h2. 效果:任意顺序的合并操作以后,包含k个节点的树的最大高度不超过lgk

void unionSet(int x, int y)
{
	fx = findset(x);
	fy = findset(y);
	if(rank[fx] > rank[fy])
	{
		set[fy] = fx;
	}
	else
	{
		set[fx] = fy;
		if(rank[fx] == rank[fy])
			rank[fy]++;
	}
}

 继续优化:

路径压缩(Path Compression) 思想:每次查找的时候,把经过路径上的点的父亲都设为根 步骤: 第一步,找到根结点 第二步,修改查找路径上的所有节点,将它们都指向根结点 可以证明m次操作的总时间复杂度为k*O(m),k是一个接近1的常数,即几乎是线性的。 使用路径压缩的并查集算法不需要再使用启发式合并。

 

 

int findSet(int x)
{
	if (x == set[x])
		return x;
	else
		return set[x] = findSet(set[x]);
}

 

I - Namesolo 拜师

给定 n 个点的图,初始没有边,要求支持以下操作:
加一条边 ( u , v )
询问 u , v 是否连通。
并查集裸题,需要注意使用快读输入,以及取模输出。

一:维护生成树

只需要维护联通性,那么只要维护一棵生成树即可。
每次询问是否连通,只需要查是否在同一棵树内,一直向上询问直到得到树根是否相同即可。
加边前先判断是否连通,若不连通,将其中一个端点设为另 一端点的双亲节点。

 期望复杂度 O(m log n),最坏复杂度 O(nm)。

二:按秩合并

设节点 x 的秩 rank x 表示以 x 为根子树树高(最深叶子到 x 的 距离),为减少树高,将秩小的节点的双亲节点设为秩大的节点。
两棵树树高不同时,最终树高等于树高较大的树的树高。
树高相同时,最终树高等于树高较大的树的树高 +1
设以 x 为根的子树节点个数为 n ,则其秩不超过 log 2 n

证明:

n = 1 时, rank x = 0 = log 2 1
假设 n = 1 , 2 , ..., k 时均满足秩不超过 log 2 n
n = k + 1 时,设 u , v 所在的树大小分别为 a , b ,其中 a b
rank u ! = rank v ,则
newrank = max ( rank u , rank v ) max ( log 2 a , log 2 b ) ≤ ⌊ log 2 n
rank u = rank v ,则
newrank = rank u + 1 ≤ ⌊ log 2 a + 1 = log 2 2 a ⌋ ≤ ⌊ log 2 n
期望复杂度 O ( m log n ) ,最坏复杂度 O ( m log n )

三:路径压缩

只需要寻找树根,重复询问同一个节点,向上询问的路径重复。 向上询问到树根形成一条路径,每次询问这条路径上的节点,都 一定会到达树根。 直接将父亲节点修改为树根,减少重复路径访问。
期望复杂度 O((n)),最坏复杂度 O(m log1+ m/n n)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值