1489. 找到最小生成树里的关键边和伪关键边

思路

基础的kruskal基础上区分两种边,首先求一下MST的Mcost:

  • 关键边,删除该边,再求MST,若cost > Mcost (或者不连通,也满足大于)则该边为关键边
  • 伪关键边,非关键边有可能是伪关键边,可以先将该边加入MST,然后继续kruskal, 若cost == Mcost吗,则为非关键边,否则“啥也不是边”

AC code

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
class Solution {
public:
const static int inf = 0x3f3f3f3f;
vector<int> p;

int find(int x){
return p[x] == x ? p[x] : p[x] = find(p[x]);
}

int kruskal(int n, vector<vector<int>>& edges, vector<int>& del){
p.resize(n);
for(int i = 0; i < n; i++) p[i] = i;
int cnt = 0;
int cost = 0;
for(auto e : edges){
if(e == del) continue;
// printVector1d(e);
int a = e[0], b = e[1], w = e[2];
int pa = find(a), pb = find(b);
if(pa != pb){
p[pa] = pb;
cnt++;
cost += w;
}
}
return cnt == n - 1 ? cost : inf;
}

int rekruskal(int n, vector<vector<int>>& edges, vector<int>& del){
p.resize(n);
for(int i = 0; i < n; i++) p[i] = i;
p[del[0]] = del[1];
int cnt = 1;
int cost = del[2];
for(auto e : edges){
if(e == del) continue;
int a = e[0], b = e[1], w = e[2];
int pa = find(a), pb = find(b);
if(pa != pb){
p[pa] = pb;
cnt++;
cost += w;
}
}
return cnt == n - 1 ? cost : inf;
}

vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
int edgen = edges.size();
for(int i = 0; i < edgen; i++) edges[i].push_back(i);
sort(edges.begin(), edges.end(), [&](const vector<int>& a, const vector<int>& b){
return a.at(2) < b.at(2);
});
vector<int> del;
int minCost = kruskal(n, edges, del);
vector<vector<int>> res(2);
for(auto e : edges){
del = e;
int cost = kruskal(n, edges, del);
//cout << i << " " << cost << endl;
if(cost > minCost) res[0].push_back(e[3]);
else if(rekruskal(n, edges, del) == minCost) res[1].push_back(e[3]);
}
return res;
}
};