题目
https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/
Kruscal算法
先用Kruscal算法计算其中一棵最小生成树的权值v,使用并查集维护连通分量。
然后遍历每一条边,去除该边重新生成最小生成树,如果最后连通分量不为1或者权值nv > v那么这条边就是关键边,然后continue。
判断是否是伪关键边可以先将当前遍历的边使用并查集进行合并,然后并查集合并完成后如果生成树的权值nv = v那么这条边就是伪关键边。
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, (o1, o2)->o1[2] - o2[2]);
UnionFind uf = new UnionFind(n);
int v = 0;
for (int i = 0; i < m; i++) {
if (uf.union(newEdges[i][0], newEdges[i][1])) {
v += newEdges[i][2];
}
}
List<List<Integer>> ans = new ArrayList<>();
ans.add(new ArrayList<>());
ans.add(new ArrayList<>());
for (int i = 0; i < m; i++) {
int nv = 0;
UnionFind uf1 = new UnionFind(n);
for (int j = 0; j < m; j++) {
if (j != i && uf1.union(newEdges[j][0], newEdges[j][1])) {
nv += newEdges[j][2];
}
}
if (uf1.count != 1 || (uf1.count == 1 && nv > v)) {
ans.get(0).add(newEdges[i][3]);
continue;
}
uf1 = new UnionFind(n);
uf1.union(newEdges[i][0], newEdges[i][1]);
nv = newEdges[i][2];
for (int j = 0; j < m; j++) {
if (j != i && uf1.union(newEdges[j][0], newEdges[j][1])) {
nv += newEdges[j][2];
}
}
if (nv == v) {
ans.get(1).add(newEdges[i][3]);
}
}
return ans;
}
private class UnionFind {
int[] parent;
int[] rank;
int count;
public UnionFind(int n) {
parent = new int[n];
rank= new int[n];
count = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public boolean union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return false;
}
if (rank[rootX] > rank[rootY]) {
int temp = rootX;
rootX = rootY;
rootY = temp;
}
parent[rootX] = rootY;
rank[rootY] += rank[rootX];
count--;
return true;
}
}
}