本章内容
本章为LeetCode-2203.
得到要求路径的最小带权子图的题解。
题目内容
给你一个整数 n ,它表示一个 带权有向图
的节点数,节点编号为 0 到 n - 1 。
同时给你一个二维整数数组 edges ,其中 \(edges[i] = [from_i, to_i, weight_i]\)
,表示从 \(from_i\) 到 \(to_i\) 有一条边权为 \(weight_i\) 的 有向
边。
最后,给你三个 互不相同 的整数src1
,src2 和 dest ,表示图中三个不同的点。
请你从图中选出一个 边权和最小 的子图,使得从 src1 和
src2 出发,在这个子图中,都 可以 到达 dest
。如果这样的子图不存在,请返回 -1 。
子图
中的点和边都应该属于原图的一部分。子图的边权和定义为它所包含的所有边的权值之和。

输入:n = 6, edges = [[0,2,2], [0,5,6], [1,0,3],
[1,4,5], [2,1,1], [2,3,3], [2,3,4], [3,4,2], [4,5,1]], src1 = 0, src2 =
1, dest = 5 输出:9
解释:
上图为输入的图。
蓝色边为最优子图之一。
注意,子图 [[1,0,3], [0,5,6]]
也能得到最优解,但无法在满足所有限制的前提下,得到更优解。
解题思路
做LeetCode比赛的时候遇到这题,刚看见的时候感觉应该不难,但因为没有时间就没能深入思考。
实际上本题不难,用的也是图论中比较经典的思想,枚举中间点,通过枚举中间点\(i\),计算src1到\(i\)的距离 + src2到\(i\)的距离 + \(i\)到dest的距离,求出最小的\(i\),上述的枚举包含所有的情况,因此直接计算即可。
求src1到\(i\)的距离可以使用Dijkstra算法,求\(i\)到dest的距离可以通过将边反向,求dest到各个点的距离来实现。
关于Dijkstra算法,本题如果不使用堆优化,会产生超时,因此顺带可以熟悉STL的使用。
STL使用 priority_queue
作为堆,默认是大根堆,因此为了得到最短路,可以将路径取相反数,放进大根堆。同时在Dijkstra算法中,用堆优化的时候,堆内的元素包含距离和顶点,因此使用
pair 记录距离和顶点。将 pair 放进
priority_queue
时,默认的排序方式是先排第一个,再排第二个。
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | class Solution {public:
 #define MAXN 100000+20
 typedef pair<long long, int> pp;
 vector<vector<int>> v1, v2, w1, w2;
 long long dis1[MAXN], dis2[MAXN], dis3[MAXN], now = -1;
 
 void getDis(int o, int n, long long *dis, int *vis, vector<vector<int>>& v, vector<vector<int>>& w)  {
 for (int i = 0; i < n; i++)  dis[i] = -1;
 priority_queue<pp> q;
 q.push(pp(0, o));
 while (!q.empty())  {
 pp p = q.top();  q.pop();
 int sn = p.second;
 long long val = -p.first;
 if (dis[sn] >= 0)  continue;
 dis[sn] = val;
 for (int i = 0; i < v[sn].size(); i++)
 q.push(pp(-val - w[sn][i], v[sn][i]));
 }
 }
 
 long long minimumWeight(int n, vector<vector<int>>& edges, int src1, int src2, int dest) {
 int vis[MAXN];
 v1 = v2 = w1 = w2 = vector<vector<int>>(n);
 
 for (auto &edge : edges)  {
 v1[edge[0]].push_back(edge[1]); w1[edge[0]].push_back(edge[2]);
 v2[edge[1]].push_back(edge[0]); w2[edge[1]].push_back(edge[2]);
 }
 
 getDis(src1, n, dis1, vis, v1, w1);
 getDis(src2, n, dis2, vis, v1, w1);
 getDis(dest, n, dis3, vis, v2, w2);
 
 for (int i = 0; i < n; i++)  {
 if (dis1[i] == -1 || dis2[i] == -1 || dis3[i] == -1)  continue;
 if (now == -1)   now = dis1[i] + dis2[i] + dis3[i];
 if (dis1[i] + dis2[i] + dis3[i] < now)
 now = dis1[i] + dis2[i] + dis3[i];
 }
 return now;
 }
 };
 
 |