acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)

Dijkstra求最短路 I:图解 详细代码(图解)

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

如果路径不存在,则输出 −1。

数据范围

1≤n≤500,
1≤m≤10^5,
图中涉及边长均不超过10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

迪杰斯特拉算法采用的是一种贪心的策略。

求源点到其余各点的最短距离步骤如下:

用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。初始时,dist 数组的各个元素为无穷大。
用一个状态数组 state 记录是否找到了源点到该节点的最短距离,state[i] 如果为真,则表示找到了源点到节点 i 的最短距离,state[i] 如果为假,则表示源点到节点 i 的最短距离还没有找到。初始时,state 各个元素为假。
acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第1张图片

源点到源点的距离为 0。即dist[1] = 0。
acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第2张图片

遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state[i] 置为 1。
acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第3张图片

遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i -> j 的距离,即 dist[j] > dist[i] + w[i][j](w[i][j] 为 i -> j 的距离) ,则更新 dist[j] = dist[i] + w[i][j]。
acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第4张图片

重复 3 4 步骤,直到所有节点的状态都被置为 1。
acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第5张图片

此时 dist 数组中,就保存了源点到其余各个节点的最短距离。

acwing-849.Dijkstra求最短路 I:图解 详细代码(图解)_第6张图片

代码

#include
using namespace std;
const int N = 510;
int g[N][N]; //领接矩阵 
int dist[N];
bool st[N];
int n, m;

int Dijkstra(){
	memset(dist, 0x3f, sizeof dist);
	
	dist[1] = 0;//源点到源点的距离为0
	//不能写st[1] = true;,因为需要每次都判断其他点到1是否走过
	//n个点n次循环 
	for(int i = 0; i < n; i++){
		//t = -1,作为这个点到他下一个第一个点 
		int t = -1;
		for(int j = 1; j <= n; j++){
			if(!st[j] && (t == -1 || dist[t] > dist[j]))
			//为了确定下一个点,要和其他每个点到源点的距离进行比较 
			t = j;
		}
		//既然到了,那就说明这个点已经确定了 
		st[t] = true;
		for(int j = 1; j <= n; j++){
			//再次更新其他点通过这个刚刚确定点到源点的距离 
			dist[j] = min (dist[j], dist[t] + g[t][j]);
		}
	}
	if(dist[n] ==  0x3f3f3f3f) return -1;
	return dist[n];
}

int main(){
	cin >> n >> m;
	memset(g, 0x3f, sizeof g);
	while (m --){
		int x, y, z;
		cin >> x >> y >> z;
		g[x][y] = min(g[x][y], z);
	}
	
	cout << Dijkstra() << endl;
	return 0;
}

你可能感兴趣的:(acwing,算法,数据结构)