Union Find 在 最小生成树(Minimum Spanning Tree)中的实现
Union Find:
顾名思义,分为两个部分 Union 和 Find:
Union:合并两个集合,也就是这将两个集合中较大的集合的root作为union后集合的root。类似于大公司合并小公司,大公司CEO同时成为小公司CEO。
Find:查询一个集合的Root。 类似于查询员工所属的CEO。
Union Find中的集合,属于树形结构,所有点指向root,root点的值为 “-size, 这里用 f 数组表示他们所属关系如下:
[ 1, 2, 4, 7]
7 => f[7] = -4
/ | \
1 2 4
f[1]=7 f[2]=7 f[4]=7
1,定义 f 数组:
public UFS (int n) { f = new int[n]; for (int i = 0; i < n; i++) { f[i] = -1; // init 初始化数组,即:每一个点都先是一个独立的集合,size = 1 } }
2,定义 Find 操作:
public int find (int x) { if (f[x] < 0) { return x; } f[x] = find(f[x]);// 如过f[x]指向一个数,就一直向上寻找到root(只有root<0) return f[x]; }
3, 定义Union 操作:
public void union(int a, int b) { a = find[a]; b = find[b];// find size of this two set if (a < b) { // a所在set比较大(因为size用负数表示) f[a] = f[a] + f[b];// 定义size=sizeA + sizeB f[b] = a;// 将较小的set的root 指向大的size的root } else { f[b] = f[b] + f[a]; f[a] = b; } }
最小生成树
- Kruskal法: 1, 边‘connection’从小到大排列; 2, 排列后扫描所有的边 ‘connection’ ,在不形成环的情况下,依次加入到图中。
例:蓝色为node, 黑线为‘边’, 边上的数字为权重。
(1) ---2---(2)--5--(5)
\ / \
7 4 9
\ / \
(3)------8-------(4)
1)排序:权重从小到大:1-2,3-5,2-5,1-3,3-4,4-5
权重: 2 4 5 7 8 9
2)按顺序加入图中,并且不能产生环:按权重顺序,在加到1-3这条边的时候,发现会产生环,所有舍弃掉,继续加3-4的边。最后加4-5的时候,发现产生环,也要舍弃。
(1) ---step1---(2)--step3--(5)
/
step2
/
(3)--step4--(4)
【LintCode】
Minimum Spanning Tree
Given a list of Connections, which is the Connection class (the city name at both ends of the edge and a cost between them), find some edges, connect all the cities and spend the least amount.
Return the connects if can connect all the cities, otherwise return empty list.
Notice
Return the connections sorted by the cost, or sorted city1 name if their cost is same, or sorted city2 if their city1 name is also same.
Gievn the connections = ["Acity","Bcity",1], ["Acity","Ccity",2], ["Bcity","Ccity",3]
Return ["Acity","Bcity",1], ["Acity","Ccity",2]
Solution:
public class Solution { /** * @param connections given a list of connections include two cities and cost * @return a list of connections from results */ int n = 0; public List<Connection> lowestCost(List<Connection> connections) { // Write your code here List<Connection> ans = new ArrayList<>(); UFS ufs = new UFS(connections.size() * 2); // sort first Collections.sort(connections, new Comparator<Connection>() { public int compare(Connection a, Connection b) { if (a.cost != b.cost) { return a.cost - b.cost; } if (a.city1.equals(b.city1)) { return a.city2.compareTo(b.city2); } return a.city1.compareTo(b.city1); } }); // union find for (Connection item : connections) { int c1 = getID(item.city1); int c2 = getID(item.city2); if (ufs.find(c1) != ufs.find(c2)) { ans.add(item); ufs.union(c1, c2); } } if (ans.size() == n - 1) { return ans; } else { return new ArrayList<>(); } } Map<String, Integer> name2ID = new HashMap<>(); // use id for city name, easy for union find public int getID(String name) { if (name2ID.containsKey(name)) { return name2ID.get(name); } else { name2ID.put(name, n++); return n - 1; } } public class UFS { int[] f; // father public UFS(int n) { f = new int[n]; for (int i = 0; i < n; i++) { f[i] = -1; } } public void union(int a, int b) { a = find(a); b = find(b); if (f[a] < f[b]) { f[a] += f[b]; f[b] = a; } else { f[b] += f[a]; f[a] = b; } } public int find(int x) { if (f[x] < 0) { return x; } f[x] = find(f[x]); return f[x]; } } }
浙公网安备 33010602011771号