给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。请你求出s号点到每个点的最短距离。
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
0 2 4 3
3 3 1
1 2 2
2 3 1
1 3 4
0 2 3
迪杰斯特拉算法过程维护两个集合S和U,S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点。由下图可以看出迪杰斯特拉算法实际上就是不断贪心地选择与起点距离最近的点,并将其从U集合中取出加入到S集合中,这个过程不断迭代,直到所有的点都被加入S。
迪杰斯特拉算法的实现就是对这个过程的模拟:
#include<bits/stdc++.h>
#define INF 0x3f
#define P pair<int, int>
using namespace std;
int d[10000], vis[10000], g[100][100]; //vis用于记录已经被走过的点
int n, m, s, cnt = 0;
priority_queue<P, vector<P>, greater<P> >a; //堆优化
void dij() {
memset(d, INF, sizeof d);
d[s] = 0; //表示除了自身之外都是不可到达的
a.push({0,s}); //把点逐个加入优先队列,按照从小到大的顺序更新周围的点
while (!a.empty()) {
int p = a.top().second;
a.pop();
if (!vis[p]) { //已经被采纳的点不用加入两次
vis[p] = 1;
for (int i = 1; i <= n; i++) {
if (d[i] > d[p] + g[p][i]) {
d[i] = d[p] + g[p][i];
a.push({d[i], i});
}
}
}
}
}
void dijkstra() {
cin >> n >> m >> s; //n个点,m条边,起点为s
memset(g, INF, sizeof g);
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
g[u][v] = w;
}
dij();
for (int i = 0; i < n; i++)
cout << d[i + 1] << " ";
}