-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlgorithm_1489_Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree.java
114 lines (104 loc) · 3.74 KB
/
Algorithm_1489_Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree.java
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 思路:Kruskal算法+并查集
// 所谓关键边,就是去掉了这条边,图的最小生成树权重值就会变化,或者根本无法构建出最小生成树
// 所谓伪关键边,就是提前加上这条边,图的最小生成树权重值不会发生变化
// https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/solution/zhao-dao-zui-xiao-sheng-cheng-shu-li-de-gu57q/
class Solution {
public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {
int m = edges.length;
int[][] newEdges = new int[m][4];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < 3; ++j) {
newEdges[i][j] = edges[i][j];
}
newEdges[i][3] = i;
}
// 按照权重从小到大排序
Arrays.sort(newEdges, new Comparator<int[]>() {
public int compare(int[] u, int[] v) {
return u[2] - v[2];
}
});
// 计算最小生成树的权重之和
UnionFind ufStd = new UnionFind(n);
int value = 0;
for (int i = 0; i < m; ++i) {
if (ufStd.unite(newEdges[i][0], newEdges[i][1])) {
value += newEdges[i][2];
}
}
List<List<Integer>> ans = new ArrayList<List<Integer>>();
for (int i = 0; i < 2; ++i) {
ans.add(new ArrayList<Integer>());
}
for (int i = 0; i < m; ++i) {
// 判断是否是关键边
UnionFind uf = new UnionFind(n);
int v = 0;
for (int j = 0; j < m; ++j) {
// 在排除第i条边的情况下,尝试构建最小生成树
if (i != j && uf.unite(newEdges[j][0], newEdges[j][1])) {
v += newEdges[j][2];
}
}
// uf.setCount != 1对应于无法构建出最小生成树
// v > value对应于新的最小生成树的权重和大于原本的最小生成树的权重和
// 这两种情况都意味着第i条边是关键边
if (uf.setCount != 1 || (uf.setCount == 1 && v > value)) {
ans.get(0).add(newEdges[i][3]);
continue;
}
// 判断是否是伪关键边
// 优先把第i条边添加到结果中,然后尝试构建最小生成树
// 如果最终得到的最小生成树的权重和v == value,说明第i条边就是伪关键边
uf = new UnionFind(n);
uf.unite(newEdges[i][0], newEdges[i][1]);
v = newEdges[i][2];
for (int j = 0; j < m; ++j) {
if (i != j && uf.unite(newEdges[j][0], newEdges[j][1])) {
v += newEdges[j][2];
}
}
if (v == value) {
ans.get(1).add(newEdges[i][3]);
}
}
return ans;
}
}
// 并查集模板
class UnionFind {
int[] parent;
int[] size;
int n;
// 当前连通分量数目
int setCount;
public UnionFind(int n) {
this.n = n;
this.setCount = n;
this.parent = new int[n];
this.size = new int[n];
Arrays.fill(size, 1);
for (int i = 0; i < n; ++i) {
parent[i] = i;
}
}
public int findset(int x) {
return parent[x] == x ? x : (parent[x] = findset(parent[x]));
}
public boolean unite(int x, int y) {
x = findset(x);
y = findset(y);
if (x == y) {
return false;
}
if (size[x] < size[y]) {
int temp = x;
x = y;
y = temp;
}
parent[y] = x;
size[x] += size[y];
--setCount;
return true;
}
}