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

难度:困难。
标签:深度优先搜索,并查集。

看了提示,需要用Kruskal算法来计算最小生成树,方法如下:

  1. 计算最小生成树的权重为 m i n W e i g h t minWeight minWeight。
  2. 遍历所有边,指定以当前边为最小生成树中的边来构建最小生成树,若构建成功且当 n o w W e i g h t = = m i n W e i g h t nowWeight == minWeight nowWeight==minWeight 时,则该边为有效边;否则(构建不成功,或构建成功权重变大)为无效边。
  3. 当边为有效边时,继续,进一步判断其为关键边或非关键边。
  4. 将当前边删除用其余边来构建最小生成树,若构建成功且 n o w W e i g h t = = m i n W e i g h t nowWeight == minWeight nowWeight==minWeight,则该边为非关键边;否则为关键边。

正确解法:

struct Edge{
    int start, end;
    int weight;
    int index;
};

bool cmp(Edge x, Edge y){
    return x.weight < y.weight;
}

void printStructArray(vector<Edge> struct_edges){
    cout << "--------------size:-------------------" << struct_edges.size() << endl;
    for(int i = 0; i < struct_edges.size(); i++){
        cout << "[ " <<  struct_edges[i].start << "," << struct_edges[i].end << "," << struct_edges[i].weight << "," << struct_edges[i].index << "]";
    }
    cout << endl << endl;
}


class unionfindSet{
    
public:
    vector<int> parent;
    vector<int> rank;

    unionfindSet(int n):parent(vector<int> (n)), rank(vector<int> (n)){
        for(int i = 0; i < n; i++){
            parent[i] = i;
        }
    }

    int find_root(int x){
        if(x != parent[x]){
            parent[x] = find_root(parent[x]);
        }
        return parent[x];
    }

    void merge(int x, int y){
        int rootx = find_root(x);
        int rooty = find_root(y);
        if(rootx != rooty){
            if(rank[rootx] < rank[rooty]){
                swap(rootx, rooty);
            }
            parent[rooty] = rootx;
            if(rank[rootx] == rank[rooty])rank[rootx] += 1;
        }
    }
};


class Solution {

    int Kruskal(vector<Edge> struct_edges, int node_num, int specified_edge=-1){
        int weight = 0;
        int MST_edge_num = 0;
        unionfindSet uf(node_num);
        // cout << "specified_edge  " << specified_edge << endl;
        if(specified_edge != -1){
            int start = struct_edges[specified_edge].start, end = struct_edges[specified_edge].end;
            // cout << "insert:[" << start << "-" << end << "]  root:" << uf.find_root(start) << " " << uf.find_root(end) <<  endl;
            uf.merge(start, end);
            MST_edge_num++;
            weight += struct_edges[specified_edge].weight;
            
        }

        for(int i = 0; i < struct_edges.size(); i++){
            if(i == specified_edge)continue;
            int start = struct_edges[i].start, end = struct_edges[i].end;
            if(uf.find_root(start) != uf.find_root(end)){
                // cout << "insert:[" << start << "-" << end << "]  root:" << uf.find_root(start) << " " << uf.find_root(end) <<  endl;
                uf.merge(start, end);
                MST_edge_num++;
                weight += struct_edges[i].weight;
            }
        }
        // cout << "MST:" << weight << " " << MST_edge_num << endl;
        if(MST_edge_num == node_num - 1)return weight;
        return -1;
    }

public:
    vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
        int edge_num = edges.size();
        vector<vector<int>> result;
        if(edge_num < n - 1)return result;
        vector<Edge> struct_edges(edge_num);
        for(int i = 0; i < edge_num; i++){
            struct_edges[i].index = i;
            struct_edges[i].start = edges[i][0];
            struct_edges[i].end = edges[i][1];
            struct_edges[i].weight = edges[i][2];
        }
        // printStructArray(edge_num);
        sort(struct_edges.begin(), struct_edges.begin() + edge_num, cmp);
        // printStructArray(struct_edges);
        int min_weight = Kruskal(struct_edges, n);
        if(min_weight == -1)return result;
        
        vector<int> critical_edges;
        vector<int> non_critical_edges;
        for(int i = 0; i < edge_num; i++){
            int weight = Kruskal(struct_edges, n, i);
            if(weight == min_weight){   // active edge
                struct Edge now_edge = struct_edges[i];
                struct_edges.erase(struct_edges.begin() + i);
                // printStructArray(struct_edges);
                int now_weight = Kruskal(struct_edges, n);
                if(now_weight == min_weight){
                    non_critical_edges.push_back(now_edge.index);
                }
                else{
                    critical_edges.push_back(now_edge.index);
                }
                struct_edges.insert(struct_edges.begin() + i, now_edge);
                // printStructArray(struct_edges);
            }
        }
        sort(critical_edges.begin(), critical_edges.end());
        sort(non_critical_edges.begin(), non_critical_edges.end());
        result.push_back(critical_edges);
        result.push_back(non_critical_edges);
        return result;
    }
};

效率很低:
LeetCode 1489. 找到最小生成树里的关键边和伪关键边
优化一下:


struct Edge{
    int start, end;
    int weight;
    int index;
};

bool cmp(Edge x, Edge y){
    return x.weight < y.weight;
}

class unionfindSet{
public:
    vector<int> parent;
    vector<int> rank;

    unionfindSet(int n):parent(vector<int> (n)), rank(vector<int> (n)){
        for(int i = 0; i < n; i++){
            parent[i] = i;
        }
    }

    int find_root(int x){
        if(x != parent[x]){
            parent[x] = find_root(parent[x]);
        }
        return parent[x];
    }

    void merge(int x, int y){
        int rootx = find_root(x);
        int rooty = find_root(y);
        if(rootx != rooty){
            if(rank[rootx] < rank[rooty]){
                swap(rootx, rooty);
            }
            parent[rooty] = rootx;
            if(rank[rootx] == rank[rooty])rank[rootx] += 1;
        }
    }
};


class Solution {

    int Kruskal(vector<Edge> struct_edges, int node_num, int specified_edge=-1, int delete_edge=-1){
        int weight = 0;
        int MST_edge_num = 0;
        unionfindSet uf(node_num);
        if(specified_edge != -1){
            int start = struct_edges[specified_edge].start, end = struct_edges[specified_edge].end;
            uf.merge(start, end);
            MST_edge_num++;
            weight += struct_edges[specified_edge].weight;
        }
        for(int i = 0; i < struct_edges.size(); i++){
            if(i == specified_edge || i == delete_edge)continue;
            int start = struct_edges[i].start, end = struct_edges[i].end;
            if(uf.find_root(start) != uf.find_root(end)){
                uf.merge(start, end);
                MST_edge_num++;
                weight += struct_edges[i].weight;
            }
            if(MST_edge_num == node_num - 1)break;
        }
        if(MST_edge_num == node_num - 1)return weight;
        return -1;
    }

public:
    vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
        int edge_num = edges.size();
        vector<vector<int>> result;
        if(edge_num < n - 1)return result;
        vector<Edge> struct_edges(edge_num);
        for(int i = 0; i < edge_num; i++){
            struct_edges[i].index = i;
            struct_edges[i].start = edges[i][0];
            struct_edges[i].end = edges[i][1];
            struct_edges[i].weight = edges[i][2];
        }

        sort(struct_edges.begin(), struct_edges.begin() + edge_num, cmp);
        int min_weight = Kruskal(struct_edges, n);
        if(min_weight == -1)return result;
        
        vector<int> critical_edges;
        vector<int> non_critical_edges;
        for(int i = 0; i < edge_num; i++){
            int weight = Kruskal(struct_edges, n, i);
            if(weight == min_weight){   // active edge
                int now_weight = Kruskal(struct_edges, n, -1, i);
                if(now_weight == min_weight){   // non-critical edge
                    non_critical_edges.push_back(struct_edges[i].index);
                }
                else{   // critical edge
                    critical_edges.push_back(struct_edges[i].index);
                }
            }
        }
        sort(critical_edges.begin(), critical_edges.end());
        sort(non_critical_edges.begin(), non_critical_edges.end());
        result.push_back(critical_edges);
        result.push_back(non_critical_edges);
        return result;
    }
};

优化了个寂寞,就这样吧,累了
LeetCode 1489. 找到最小生成树里的关键边和伪关键边

上一篇:PAT甲级1154Vertex Coloring


下一篇:常用十大算法(七)— 克鲁斯卡尔算法