单源最短路径,Dijkstra | 洛谷 P4779 【模板】单源最短路径(标准版)

题目传送门

题意

给定一个 n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。

数据保证你能从 s 出发到任意点。

分析

关于 SPFA,它死了。

Dijkstra 算法由荷兰计算机科学家 E. W. Dijkstra 于 1956 年发现,1959 年公开发表。是一种求解 非负权图 上单源最短路径的算法。优先队列优化的 Dijkstra 算法的时间复杂度为 O(mlogm)

然后重复以下操作:

  • 每次寻找一个 dis 最小的点,然后对所有出边进行 松弛(relax) 操作。即对于每个点 u,都用它将相邻的所有点 vdis 值更新的过程。具体来说,更新过程为 min(disv, disu+wu,v)

直到松弛操作扩散到所有的点,算法结束。

代码

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;

struct edge{
	int to, w, nxt;
}e[N];

int n, m, u, v, w, s, head[N], dis[N];
bool vis[N];

inline void add_edge(int u, int v, int w, int id){
	e[id] = {v, w, head[u]};
	head[u] = id;
}

struct node{
	int id, dis; // 结构体记录每个点的编号和最短路长度
	bool operator < (const node &x) const{ // 重载运算符
		return dis > x.dis;
	}
};

inline void Dijkstra(int s){
	priority_queue<node> q;
	memset(dis, 0x3f, sizeof dis);
	memset(vis, 0, sizeof vis);
	dis[s] = 0, q.push({s, 0}); // 将起点放入队列
	while(!q.empty()){ // 当队列非空(即没有遍历完所有的店)
		u = q.top().id; q.pop(); // 取出队首(由于使用了优先队列,队首即为 dis 最小的点)
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = head[u]; ~i; i = e[i].nxt){ // 遍历所有出边
			v = e[i].to;
			if(dis[v] > dis[u] + e[i].w){ // 松弛操作
				dis[v] = dis[u] + e[i].w;
				if(!vis[v]) q.push({v, dis[v]}); // 遍历到 v,则将 v 也加入队列
			}
		}
	}
	return;
}

int main(){
	ios::sync_with_stdio(false);
	memset(head, -1, sizeof head);
	cin >> n >> m >> s;
	for(int i = 1; i <= m; i++){
		cin >> u >> v >> w;
		add_edge(u, v, w, i);
	}
	Dijkstra(s);
	for(int i = 1; i <= n; i++)
		cout << dis[i] << ' '; // 依次输出每个点的 dis 值
	return 0;
}
posted @   心灵震荡  阅读(18)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示