「学习笔记」最短路

uv 的最短路径的长度就是 uv 的最短路。
单源最短路算法可以求出一个点到其他点的最短路。
全源最短路算法可以求出每一个点到其他各点的最短路。
松弛操作:dis[v] = min(dis[v], dis[u] + w);

算法#

Floyd 算法#

全源最短路算法,时间复杂度 On3,空间复杂度 On2,用了 DP 的思想。

实现

设数组 f[x][y],含义:xy 的最短路。
转移:f[x][y] = min(f[x][y], f[x][k] + f[k][y]);
k 为除了 xy 的其他节点。

for (int k = 1; k <= n; ++ k) {
	for (int i = 1; i <= n; ++ i) {
		for (int j = 1; j <= n; ++ j) {
			f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
		}
	}
}

dijkstra 算法#

单源最短路算法,时间复杂度 On2,运用了贪心的思想。

实现

将点分为两部分,已经确定最短路的点和没确定最短路的点,记已确定最短路的点的集合为 S,未确定最短路的点的集合为 T
s 为起点,初始时设 dis[s] = 0,其他节点的 dis 设为 inf
T 中取一个最短路最小的点,将它转移到 S 集合去,并用它来更新其他点的最短路,重复此操作,直到 T 为空。

这里用最短路最小点的来更新答案就是运用了贪心的思想。

int n;
int dis[N], vis[N];
vector<pair<int, int> > son[N];

void dij(int s) {
	for (int i = 0; i <= n; ++ i) {
		dis[i] = inf;
	}
	dis[s] = 0;
	for (int i = 1; i < n; ++ i) {
		int u = 0, minn = inf;
		for (int j = 1; j <= n; ++ j) {
			if (vis[j] || dis[j] >= minn)	continue;
			u = j;
			minn = dis[j];
		}
		vis[u] = true;
		for (auto it : son[u]) {
			int v = it.first, w = it.second;
			dis[v] = min(dis[v], dis[u] + w);
		}
	}
}

优化

我们每次从剩下的元素中取最小的,进行 n 次,复杂度为 Onlogn,但是,我们可以用小根堆堆来使得这步操作的时间复杂度降低至 Onlogn,于是,就有了 dijkstra 的堆优化版本。

typedef pair<int, ll> pil;

void dij(int st) {
	priority_queue<pil, vector<pil>, greater<pil> > q;
	for (int i = 1; i <= n; ++i) {
		dis[i] = 1e9;
		vis[i] = 0;
	}
	dis[st] = 0;
	q.push(make_pair(0, st));
	while (!q.empty()) {
		int u = q.top().second;
		q.pop();
		if (vis[u])	continue;
		vis[u] = 1;
		for (int i = h[u]; i; i = e[i].nxt) {
			int v = e[i].v;
			if (dis[v] > dis[u] + e[i].w) {
				dis[v] = dis[u] + e[i].w;
				q.push(make_pair(dis[v], v));
			}
		}
	}
}

不管是朴素版本的 dijkstra,还是堆优化版本的 dijkstra,都要求图的边权不为负边权。

Bellman-Ford 算法#

这个算法或许有些人没听说过,但是它的优化版本你肯定听过,SPFA。
单源最短路算法,时间复杂度 Onm

实现

每一次松弛操作都会产生一条最短路,如果一个图中不存在负环,最多会松驰 n1 次。

for (int i = 1; i <= n; ++ i) {
	dis[i] = inf;
}
dis[s] = 0;
for (int i = 1; i <= n; ++ i) {
	for (int j = 1; j <= m; ++ j) {
		dis[v[j]] = min(dis[v[j]], dis[u[j]] + w[j]);
	}
}

SPFA 算法#

关于SPFA,它。。。
SPFA算法是 Bellman-Ford 算法的队列优化版本,最坏时间复杂度为 Onm,一般跑得很快。

实现

给原先的 Bellman-Ford 加一个队列即可。

void spfa(int s) {
	queue<int> q;
	for (int i = 1; i <= n; ++ i) {
		dis[i] = inf;
		vis[i] = 0;
	}
	dis[s] = 0;
	q.push(s);
	vis[s] = 1;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for (auto it : son[u]) { 
			int v = it.first, w = it.second; 
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (! vis[v]) {
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
}

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/17363015.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示