【图论】单源最短路径 Dijkstra

单源出发,最短路径,松弛。

Dijkstra 算法是所有最短路径算法中某种意义上最快的,只是代码略为难写。

松弛

Dijkstra 算法的精髓,就是两个字:松弛。包括所有的最短路径算法,都依靠的是这个词。
何为松弛?假设现有若干个点,点 \(v\) 到起点的最短路径很大,但是有另一个点 \(u\),它的路径值较小,而且它与 \(v\) 相连,则可以用 \(u\) 点的路径值加上边权值得出更优的 \(v\) 的路径值,即 \(dis_v=min(dis_v,dis_u+w)\)

类似于 BFS 的代码结构

Dijkstra 类似一个 BFS,每次从一个顶点(已经被更新过的)更新所有它能更新的结点。而选出的这个结点就是已经更新过的结点中路径值的最小值。
不要忘记判断是否重复利用某个点。
我们可以采用优先队列(堆)来实现这个最小值的需求。

初始化

每个点的最初路径值都是 \(\infty\),只有起始结点的值为 \(0\),很好理解。

代码

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const ll MAXN = 200005;
const ll INF = 2147483647;
struct Edge{
	ll v, w;
};
vector<Edge> adj[MAXN];
struct Que{
	ll d, v;
	bool operator <(const Que &o)const{
		return v > o.v;
	}
};
ll n, m, dis[MAXN], vis[MAXN];
priority_queue<Que> q;
void Dijkstra(ll s){
	for(ll i = 1; i <= n; i ++){
		dis[i] = INF;
		vis[i] = 0;
	}
	dis[s] = 0;
	q.push({s, 0});
	while(!q.empty()){
		ll u = q.top().d;
		q.pop();
		if(vis[u])continue;
		vis[u] = 1;
		for(auto it : adj[u]){
			ll v = it.v, w = it.w;
			if(dis[u] + w < dis[v]){
				dis[v] = dis[u] + w;
				q.push({v, dis[v]});
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll s;
	cin >> n >> m >> s;
	for(ll i = 1; i <= m; i ++){
		int u, v, w;
		cin >> u >> v >> w;
		adj[u].push_back({v, w});
	}
	Dijkstra(s);
	for(ll i = 1; i <= n; i ++){
		cout << dis[i] << " ";
	}
	return 0;
}
posted @ 2024-12-06 22:15  Allenyang_Tco  阅读(17)  评论(0编辑  收藏  举报