Union Find 并查集

Dynamic connectivity:

Union Command: connect two objects

Find query: is there a path connecting the two objects?


Quick Find:

用一个数组来表示所有connected component。每个数字顶点在数组中都有一个set index。如果两个顶点的set index是一样的,则表示它们是连接的。

容易find,但union复杂。union(a,b) 将a所在的connected component的set index改成b的set index。

public class QuickFind {
	private int[] id;

	public QuickFind(int N) {
		id = new int[N];
		// Initialization
		for (int i = 0; i < N; i++) {
			id[i] = i;
		}
	}
	// O(1) access
	public boolean connected(int p, int q) {
		return id[p] == id[q];
	}
	// O(N) access
	public void union(int p, int q) {
		int pid = id[p];
		int qid = id[q];
		for (int i = 0; i < id.length; i++) {
			if (id[i] == pid) {
				id[i] = qid;
			}
		}
	}
}

Quick Union:

树形结构,每个数字顶点都有一个set index,指向它的parent顶点。每个数字顶点都有一个root,如果两个顶点的root一样,则表示它们是连接的。

Weighted Quick Union:

总是把小的树作为子树。Always put smaller tree below. 树最深为lgN

Path Compression:

所经路径顶点都指向root。

WQUPC:

public class QuickUnion {
	private int[] id;
	private int[] size;

	public QuickUnion(int N) {
		id = new int[N];
		size = new int[N];
		for (int i = 0; i < N; i++) {
			id[i] = i;
			size[i] = 1;
		}
	}

	private int root(int i) {
		while (i != id[i]) {
			id[i] = id[id[i]]; // Path compression
			i = id[i];
		}
		return i;
		// return i == id[i] ? i : root(id[i]); no path compression
	}

	public boolean connected(int p, int q) {
		return root(p) == root(q);
	}

	public void union(int p, int q) {
		int proot = root(p);
		int qroot = root(q);
		if (proot == qroot) {
			return;
		}
		// Smaller tree as subtree of larger tree
		if (size[proot] < size[qroot]) {
			id[proot] = qroot;
			size[qroot] += size[proot];
		} else {
			id[qroot] = proot;
			size[proot] += size[qroot];
		}
	}
}

应用:

Percolation:

黑白块,如果从上到下有白块通路,则system percolates。


0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63


0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63


public class Percolation {
	private int[] id;
	private int[] size;
	private boolean[] color;
	private int width;
	private int top;
	private int bot;

	public Percolation(int N) {
		width = N;
		top = N * N;
		bot = top + 1;
		id = new int[N * N + 2];
		size = new int[N * N + 2];
		color = new boolean[N * N + 2];
		for (int i = 0; i < N * N + 2; i++) {
			id[i] = i;
			size[i] = 1;
		}
		color[top] = true;
		color[bot] = true;
	}

	private int root(int i) {
		while (i != id[i]) {
			id[i] = id[id[i]];
			i = id[i];
		}
		return i;
	}

	public boolean connected(int p, int q) {
		return root(p) == root(q);
	}

	public void union(int p, int q) {
		int proot = root(p);
		int qroot = root(q);
		if (proot == qroot) {
			return;
		}
		if (size[proot] <= size[qroot]) {
			id[proot] = qroot;
			size[qroot] += size[proot];
		} else {
			id[qroot] = proot;
			size[proot] += size[qroot];
		}
	}

	public void openSite(int p) {
		color[p] = true;
		if (p < width) {
			union(p, top);
		}
		if (p >= (width - 1) * width) {
			union(p, bot);
		}
		int row = p / width;
		int col = p % width;
		if (row - 1 >= 0 && color[p - width]) {
			union(p, p - width);
		}
		if (row + 1 < width && color[p + width]) {
			union(p, p + width);
		}
		if (col - 1 >= 0 && color[p - 1]) {
			union(p, p - 1);
		}
		if (col + 1 < width && color[p + 1]) {
			union(p, p + 1);
		}
	}

	public boolean isPercolate() {
		return root(top) == root(bot);
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < width * width; i++) {
			if (color[i]) {
				sb.append("O");
			} else {
				sb.append("X");
			}
			if ((i + 1) % width == 0) {
				sb.append('\n');
			}
		}
		sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值