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

给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。

请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。

请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。

 

示例 1:

输入:n = 5, edges = [[0,1,1],[1,2,1],[2,3,2],[0,3,2],[0,4,3],[3,4,3],[1,4,6]]
输出:[[0,1],[2,3,4,5]]
解释:上图描述了给定图。
下图是所有的最小生成树。

注意到第 0 条边和第 1 条边出现在了所有最小生成树中,所以它们是关键边,我们将这两个下标作为输出的第一个列表。
边 2,3,4 和 5 是所有 MST 的剩余边,所以它们是伪关键边。我们将它们作为输出的第二个列表。

示例 2 :

输入:n = 4, edges = [[0,1,1],[1,2,1],[2,3,1],[0,3,1]]
输出:[[],[0,1,2,3]]
解释:可以观察到 4 条边都有相同的权值,任选它们中的 3 条可以形成一棵 MST 。所以 4 条边都是伪关键边。

 

提示:

  • 2 <= n <= 100
  • 1 <= edges.length <= min(200, n * (n - 1) / 2)
  • edges[i].length == 3
  • 0 <= fromi < toi < n
  • 1 <= weighti <= 1000
  • 所有 (fromi, toi) 数对都是互不相同的。

 

vector<int>pre(120,0);

class Solution {//disjoint set to avoid adding redundant edges that result in a cycle.
    int find(int x){
        if(x==pre[x])return x;
        else return find(pre[x]);
    }

public:
    int NotIncludeEdge(int n,vector<vector<int>>& edges,int notIncludeEdge){
        for(int i=0;i<pre.size();i++)
            pre[i]=i;
        int MST=0;
        int edgenum=0;
        for(auto &edge:edges){
            if(edge[3]==notIncludeEdge)continue;
            int a=find(edge[1]);
            int b=find(edge[2]);
            if(a!=b){
                edgenum++;
                MST+=edge[0];
                if(edgenum==n-1)
                    break;//break before resulting in a cycle
                pre[a]=b;
            }
        }
        if(edgenum==n-1)
            return MST;
        else
            return INT_MAX;
    }

    int IncludeEdge(int n,vector<vector<int>>& edges,int includeEdge){
        for(int i=0;i<pre.size();i++)
            pre[i]=i;
        int MST=0;
        int edgenum=0;
        for(auto &edge:edges){
            if(edge[3]==includeEdge){
                edgenum++;
                MST+=edge[0];
                pre[edge[1]]=edge[2];
                break;
            }
        }
        for(auto &edge:edges){
            int a=find(edge[1]);
            int b=find(edge[2]);
            if(a!=b){
                edgenum++;
                MST+=edge[0];
                if(edgenum==n-1)
                    break;//break before resulting in a cycle
                pre[a]=b;
            }
        }
        if(edgenum==n-1)
            return MST;
        else
            return INT_MAX;
    }

    vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& _edges) {
        int i=0;
        for(auto &edge:_edges){
            swap(edge[0],edge[2]);
            edge.push_back(i);
            i++;
        }
        sort(_edges.begin(),_edges.end());//Kruskal algorithm to find the minimum spanning tree
        int MST=NotIncludeEdge(n,_edges,-1);
        vector<vector<int>>res(2);
        i=0;
        for(auto &edge:_edges){
            int costNotIn=NotIncludeEdge(n,_edges,i);
            int costIn=IncludeEdge(n,_edges,i);
            if(costNotIn>MST)res[0].push_back(i);//if the new MST increases,then the deleted edge is critical
            else if(costIn==MST)res[1].push_back(i);//if the new MST is the same,then the included edge is non-critical
            i++;
        }
        return res;
    }
};

 

posted @ 2021-01-23 22:06  XXXSANS  阅读(118)  评论(0编辑  收藏  举报