给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。
请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。
请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。
输入: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) 数对都是互不相同的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
vector<int> pointConnect(120,0);
class Solution {
int findConnect(int i)
{
if(pointConnect[i] != i)
{
pointConnect[i] = findConnect(pointConnect[i]);
}
return pointConnect[i];
}
public:
//计算不包括某条边的最小路径权值
int computerNotIncludeOneEdge(int n,vector<vector<int> >& edges,int notIncludeEdge)
{
for(int i = 0; i < pointConnect.size(); i++) pointConnect[i] = i;
int cost = 0;
int edgeNum = 0;
for(auto& edge : edges)
{
if( edge[3] == notIncludeEdge) continue;
int pointStart = findConnect(edge[1]);
int pointEnd = findConnect(edge[2]);
if(pointStart != pointEnd)
{
edgeNum++;
cost += edge[0];
if(edgeNum == n-1)
break;
pointConnect[pointStart] = pointEnd;
}
}
if(edgeNum == n-1)
return cost;
else
return INT_MAX;
}
//计算包括某条边的最小路径权值
int computerIncludeOneEdge(int n,vector<vector<int> >& edges,int includeEdge)
{
for(int i = 0; i < pointConnect.size(); i++) pointConnect[i] = i;
int cost = 0;
int edgeNum = 0;
for(auto & edge : edges)
{
if(edge[3] == includeEdge)
{
edgeNum++;
cost += edge[0];
pointConnect[edge[1]] = edge[2];
break;
}
}
for(auto& edge : edges)
{
int pointStart = findConnect(edge[1]);
int pointEnd = findConnect(edge[2]);
if(pointStart != pointEnd)
{
edgeNum++;
cost += edge[0];
if(edgeNum == n-1)
break;
pointConnect[pointStart] = pointEnd;
}
}
if(edgeNum == n-1)
return cost;
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());
//求出最小生成树的权值和 采用kuskal算法
int minCost = computerNotIncludeOneEdge(n,_edges,-1);
//不包括某条路径是否会造成权值变大或不连通,即关键边
//包括某条路径不会造成权值变大,即伪关键边
vector<vector<int>> ans(2);
i = 0;
for(auto & edge : _edges)
{
int costNotIn = computerNotIncludeOneEdge(n,_edges,i);
int costIn = computerIncludeOneEdge(n,_edges,i);
if(costNotIn > minCost) ans[0].push_back(i);
else if(costIn == minCost) ans[1].push_back(i);
i++;
}
return ans;
}
};