当前位置:   article > 正文

第7周博客,并查集笔记

第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 的父节点.

  1. int findSet(int x)
  2. {
  3. if (x == set[x])
  4. return x;
  5. else
  6. return findSet(set[x]);
  7. }
  8. void unionSet(int x, int y)
  9. {
  10. int fx = findSet(x);
  11. int fy = findSet(y);
  12. set[fy] = fx;
  13. }

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

  1. void unionSet(int x, int y)
  2. {
  3. fx = findset(x);
  4. fy = findset(y);
  5. if(rank[fx] > rank[fy])
  6. {
  7. set[fy] = fx;
  8. }
  9. else
  10. {
  11. set[fx] = fy;
  12. if(rank[fx] == rank[fy])
  13. rank[fy]++;
  14. }
  15. }

 继续优化:

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

 

 

  1. int findSet(int x)
  2. {
  3. if (x == set[x])
  4. return x;
  5. else
  6. return set[x] = findSet(set[x]);
  7. }

 

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)。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/786651
推荐阅读
相关标签
  

闽ICP备14008679号