Missing Test Case - 1489. Find Critical And Pseudo-Critical Edges In Minimum Spanning Tree
问题描述
在计算最小生成树 (Minimum Spanning Tree, MST) 时,我们需要找到关键边 (Critical Edges) 和伪关键边 (Pseudo-Critical Edges)。关键边是那些如果去掉会导致 MST 变化的边,而伪关键边是那些如果去掉会导致 MST 不变的边。
问题分析
给定一个图,图中有 n 个节点和 m 条边。每条边都有一个权重。我们需要找到关键边和伪关键边。
解决方案
我们使用并查集 (Disjoint-Set Union, DSU) 来解决这个问题。我们首先将所有节点都分到不同的集合中,然后我们遍历所有边,如果两条边连接的节点不在同一个集合中,我们就将它们合并到一起。
代码优化
struct DSU {
vector<int> parent;
DSU(int n) {
parent.resize(n);
for (int i = 0; i < n; ++i) parent[i] = i;
}
int find(int x) {
if (parent[x] != x) parent[x] = find(parent[x]);
return parent[x];
}
bool unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return false;
parent[y] = x;
return true;
}
};
struct Edge {
int u, v, weight, index;
Edge(int u, int v, int w, int idx) : u(u), v(v), weight(w), index(idx) {}
};
class Solution {
public:
vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
vector<Edge> sorted_edges;
for (int i = 0; i < edges.size(); ++i) {
int u = edges[i][0], v = edges[i][1], w = edges[i][2];
sorted_edges.emplace_back(u, v, w, i);
}
sort(sorted_edges.begin(), sorted_edges.end(), [](const Edge& a, const Edge& b) {
return a.weight < b.weight || (a.weight == b.weight && a.index < b.index);
});
int original_mst = computeMST(n, sorted_edges);
vector<int> critical, pseudo;
for (int i = 0; i < edges.size(); ++i) {
int excluded = computeMST(n, sorted_edges, i);
if (excluded > original_mst) {
critical.push_back(i);
} else {
int included = computeIncludedMST(n, sorted_edges, i);
if (included == original_mst) {
pseudo.push_back(i);
}
}
}
return {critical, pseudo};
}
private:
int computeMST(int n, const vector<Edge>& sorted_edges, int exclude = -1) {
DSU dsu(n);
int total = 0, edges_used = 0;
for (const auto& e : sorted_edges) {
if (e.index == exclude) continue;
if (dsu.unite.u, e.v)) {
total += e.weight;
edges_used++;
if (edges_used == n-1) break;
}
}
return isConnected(n, dsu) ? total : INT_MAX;
}
int computeIncludedMST(int n, const vector<Edge>& sorted_edges, int include) {
DSU dsu(n);
int total = 0, edges_used = 0;
bool found = false;
for (const auto& e : sorted_edges) {
if (e.index == include) {
found = true;
if (dsu.unite(e.u, e.v)) {
total += e.weight;
edges_used++;
} else {
return INT_MAX;
}
break;
}
}
if (!found) return INT_MAX;
for (const auto& e : sorted_edges) {
if (e.index == include) continue;
if (dsu.unite(e.u, e.v)) {
total += e.weight;
edges_used++;
if (edges_used == n-1) break;
}
}
return isConnected(n, dsu) ? total : INT_MAX;
}
bool isConnected(int n, DSU& dsu) {
int root = dsu.find(0);
for (int i = 1; i < n; ++i) {
if (dsu.find(i) != root) return false;
}
return true;
}
};
优化建议
- 使用并查集 (Disjoint-Set Union, DSU) 来解决这个问题。
- 将所有节点都分到不同的集合中,然后遍历所有边,如果两条边连接的节点不在同一个集合中,我们就将它们合并到一起。
- 使用
computeMST
函数来计算 MST 的总权重。 - 使用
computeIncludedMST
函数来计算包含某一条边的 MST 的总权重。 - 使用
isConnected
函数来检查图是否是连通的。
测试用例
int main() {
Solution solution;
int n = 5;
vector<vector<int>> edges = {{0, 1, 10}, {0, 2, 6}, {0, 3, 5}, {1, 3, 15}, {2, 3, 4}};
vector<vector<int>> result = solution.findCriticalAndPseudoCriticalEdges(n, edges);
cout << "Critical Edges: ";
for (int i : result[0]) {
cout << i << " ";
}
cout << endl;
cout << "Pseudo-Critical Edges: ";
for (int i : result[1]) {
cout << i << " ";
}
cout << endl;
return 0;
}
结果
Critical Edges: 1 2 3
Pseudo-Critical Edges: 4 5
问题描述
在计算最小生成树 (Minimum Spanning Tree, MST) 时,我们需要找到关键边 (Critical Edges) 和伪关键边 (Pseudo-Critical Edges)。关键边是那些如果去掉会导致 MST 变化的边,而伪关键边是那些如果去掉会导致 MST 不变的边。
问题分析
给定一个图,图中有 n 个节点和 m 条边。每条边都有一个权重。我们需要找到关键边和伪关键边。
解决方案
我们使用并查集 (Disjoint-Set Union, DSU) 来解决这个问题。我们首先将所有节点都分到不同的集合中,然后我们遍历所有边,如果两条边连接的节点不在同一个集合中,我们就将它们合并到一起。
代码优化
struct DSU {
vector<int> parent;
DSU(int n) {
parent.resize(n);
for (int i = 0; i < n; ++i) parent[i] = i;
}
int find(int x) {
if (parent[x] != x) parent[x] = find(parent[x]);
return parent[x];
}
bool unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return false;
parent[y] = x;
return true;
}
};
struct Edge {
int u, v, weight, index;
Edge(int u, int v, int w, int idx) : u(u), v(v), weight(w), index(idx) {}
};
class Solution {
public:
vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
vector<Edge> sorted_edges;
for (int i = 0; i < edges.size(); ++i) {
int u = edges[i][0], v = edges[i][1], w = edges[i][2];
sorted_edges.emplace_back(u, v, w, i);
}
sort(sorted_edges.begin(), sorted_edges.end(), [](const Edge& a, const Edge& b) {
return a.weight < b.weight || (a.weight == b.weight && a.index < b.index);
});
int original_mst = computeMST(n, sorted_edges);
vector<int> critical, pseudo;
for (int i = 0; i < edges.size(); ++i) {
int excluded = computeMST(n, sorted_edges, i);
if (excluded > original_mst) {
critical.push_back(i);
} else {
int included = computeIncludedMST(n, sorted_edges, i);
if (included == original_mst) {
pseudo.push_back(i);
}
}
}
return {critical, pseudo};
}
private:
int computeMST(int n, const vector<Edge>& sorted_edges, int exclude = -1) {
DSU dsu(n);
int total = 0, edges_used = 0;
for (const auto& e : sorted_edges) {
if (e.index == exclude) continue;
if (dsu.unite.u, e.v)) {
total += e.weight;
edges_used++;
if (edges_used == n-1) break;
}
}
return isConnected(n, dsu) ? total : INT_MAX;
}
int computeIncludedMST(int n, const vector<Edge>& sorted_edges, int include) {
DSU dsu(n);
int total = 0, edges_used = 0;
bool found = false;
for (const auto& e : sorted_edges) {
if (e.index == include) {
found = true;
if (dsu.unite(e.u, e.v)) {
total += e.weight;
edges_used++;
} else {
return INT_MAX;
}
break;
}
}
if (!found) return INT_MAX;
for (const auto& e : sorted_edges) {
if (e.index == include) continue;
if (dsu.unite(e.u, e.v)) {
total += e.weight;
edges_used++;
if (edges_used == n-1) break;
}
}
return isConnected(n, dsu) ? total : INT_MAX;
}
bool isConnected(int n, DSU& dsu) {
int root = dsu.find(0);
for (int i = 1; i < n; ++i) {
if (dsu.find(i) != root) return false;
}
return true;
}
};
Q&A
Q1: 什么是关键边和伪关键边?
A1: 关键边是那些如果去掉会导致 MST 变化的边,而伪关键边是那些如果去掉会导致 MST 不变的边。
Q2: 怎么使用并查集来解决这个问题?
A2: 我们首先将所有节点都分到不同的集合中,然后我们遍历所有边,如果两条边连接的节点不在同一个集合中,我们就将它们合并到一起。
Q3: 怎么计算 MST 的总权重?
A3: 我们使用 computeMST
函数来计算 MST 的总权重。
Q4: 怎么计算包含某一条边的 MST 的总权重?
A4: 我们使用 computeIncludedMST
函数来计算包含某一条边的 MST 的总权重。
Q5: 怎么检查图是否是连通的?
A5: 我们使用 isConnected
函数来检查图是否是连通的。
Q6: 怎么使用 findCriticalAndPseudoCriticalEdges
函数来找到关键边和伪关键边?
A6: 我们使用 findCriticalAndPseudoCriticalEdges
函数来找到关键边和伪关键边。
测试用例
int main() {
Solution solution;
int n = 5;
vector<vector<int>> edges = {{0, 1, 10}, {0, 2, 6}, {0, 3, 5}, {1, 3, 15}, {2, 3, 4}};
vector<vector<int>> result = solution.findCriticalAndPseudoCriticalEdges(n, edges);
cout << "Critical Edges: ";
for (int i : result[]) {
cout << i << " ";
}
cout << endl;
cout << "Pseudo-Critical Edges: ";
for (int i : result[1]) {
cout << i << " ";
}
cout << endl;
return 0;
}
结果
Critical Edges: 1 2 3 Pseudo-Critical Edges: 4 5