并查集
方法1:
用编号最小的元素标记所在集合;
定义一个数组 set[1..n] ,其中set[i] 表示元素i 所在的集合;
O(1): find1(x) { return set[x]; } O(n) Merge1(a,b) { i = min(a,b); j = max(a,b); for (k=1; k<=N; k++) { if (set[k] == j) set[k] = i; } }
方法2;
每个集合用一棵“有根树”表示定义数组 set[1..n]
set[i] = i , 则i表示本集合,并是集合对应树的根 set[i] = j, j != i, 则 j 是 i 的父节点. find2(x) { r = x; while (set[r] != r) r = set[r]; return r; } //O(n) merge2(a, b) { if (a<b) set[b] = a; else set[a] = b; }//O(1)
带路径压缩的查找算法
第一步,找到根结点
第二步,修改查找路径上的所有节点,将它们都指向根结点
find3(x) { r = x; while (set[r] <> r) //循环结束,则找到根节点 r = set[r]; i = x; while (i <> r) //本循环修改查找路径中所有节点 { j = set[i]; set[i] = r; i = j; } }
//并查集练习
HDOJ-1558 Segment set
HDOJ-1811 Rank of Tetris
HDOJ-1829 A Bug's Life
HDOJ-1198 Farm Irrigation
ZOJ 2740