题解 | #【模板】单源最短路2#
【模板】单源最短路2
https://www.nowcoder.com/practice/7c1740c3d4ba4b3486df4847ee6e8fc7
本题使用邻接矩阵进行建图,使用Dijkstra算法求单源最短路。
1.建图:本题图中的顶点数已经给定固定值
N = 5000
,因此使用二维数组G[N + 1][N + 1]
作为邻接矩阵进行建图,两点间无连接时使用无穷大(程序中使用INT_MAX
)表示。同时本题为无向图,因此建图时需要注意邻接矩阵关于主对角线对称。
2.求解单源最短路:使用Dijkstra算法(即不断从未处理集合中找当前距离源点最近的顶点以添加到已处理集合中,直至未处理集合为空的算法思想)。
首先需要定义一个dist
数组用于存储每个顶点当前与源点(出发点)的最短距离(权值),还需要定义一个flag
数组用于记录每个顶点是否已经完成与源点最短距离的计算处理(即标识了是否添加到了已处理集合中)。
初始时将dist
数组设置为邻接矩阵G
中源点所在行的权值,将flag
数组全部设置为false
,之后将源点位置的dist
值设置为0
,flag
设置为true
,表示将源点加入已处理集合且与源点的距离为0
。之后循环顶点数减一(除源点外的其他顶点)次,每次找到未处理集合中距离源点最近的顶点,将其flag
值设置为true
(即加入已处理集合中),之后再使用 该距离加上该顶点与其他未处理集合中的顶点的距离 和 源点与其他未处理集合中的顶点的距离 相比较,更新距离的最短值。
最终判断dist[n]
处的结果是否为无穷大,若是表示无法到达输出-1
,若否则直接输出即为最短距离。
#include<iostream> #include<climits> // 使用INT_MAX所需要引入的头文件 using namespace std; int main() { const int N = 5000; // 注意题干,图的点数是固定值5000 int G[N + 1][N + 1]; // 用于模拟邻接矩阵进行建图 for(int i = 1; i <= N; i++) { for(int j = 1; j <= N; j++) { G[i][j] = INT_MAX; // 先将邻接矩阵全部初始化为无穷大 } } int n, m; cin>>n>>m; int u, v, w; for(int i = 1; i <= m; i++) { cin>>u>>v>>w; G[u][v] = w; G[v][u] = w; // 注意为无向图,需要关于主对角线对称,因此两边都需要存储 } int dist[N + 1]; // 用于存储每个顶点当前与源点的最短距离 bool flag[N + 1]; // 用于记录每个顶点是否已经完成与源点最短距离的计算处理 for(int i = 1; i <= N; i++) { dist[i] = G[1][i]; // 初始设置为邻接矩阵中源点所在 行 的权值 flag[i] = false; } dist[1] = 0; flag[1] = true; // 将源点加入已处理集合 for(int i = 2; i <= N; i++) { int tmp = INT_MAX, index = 1; for(int j = 1; j <= N; j++) // 遍历寻找与源点的最短距离 { if(flag[j] == false && dist[j] < tmp) { tmp = dist[j]; index = j; } } if(index != 1) { flag[index] = true; // 找到后将其加入已处理集合 } for(int j = 1; j <= N; j++) { if(flag[j] == false && G[index][j] != INT_MAX) { if(G[index][j] + dist[index] < dist[j]) { dist[j] = G[index][j] + dist[index]; // 新的距离比原距离更短,则进行更新 } } } } if(dist[n] != INT_MAX) { cout<<dist[n]; } else // 没有从源点到达该顶点的边 { cout<<-1; } return 0; }