Missing Test Case - 1489. Find Critical And Pseudo-Critical Edges In Minimum Spanning Tree

by ADMIN 91 views

问题描述

在计算最小生成树 (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;
    }
};

优化建议

  1. 使用并查集 (Disjoint-Set Union, DSU) 来解决这个问题。
  2. 将所有节点都分到不同的集合中,然后遍历所有边,如果两条边连接的节点不在同一个集合中,我们就将它们合并到一起。
  3. 使用 computeMST 函数来计算 MST 的总权重。
  4. 使用 computeIncludedMST 函数来计算包含某一条边的 MST 的总权重。
  5. 使用 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