Johnson 全源最短路
Johnson 全源最短路
Johnson 和 Floyd 一样是能求出无负环图上任意两点间最短路径的算法。
引入#
求任意两点间的最短路可以通过枚举起点,跑
或者我们可以跑
但是 Dijkstra 有一个致命的缺陷就是他不能处理负边权。
我们不难想到来修改边权使其为正数。
核心思想#
我们新建一个虚拟的节点,假设他的编号为
接下来我们跑一遍 SPFA,求出零号点到所有点的最短路记为
如果存在一条边
接下来以每一个点为起点跑
复杂度为
正确性#
我们考虑找到从
那么这条路径的长度就是:
展开就是:
所以无论怎么走,只要是
Q:你说的对,但是为什么能保证修改后的边权都是非负数?
根据
code#
#include <bits/stdc++.h>
#define pii pair<int, int>
#define INF 1000000000
#define int long long
#define N 10010
#define endl '\n'
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, m, t, head[N], vis[N], cnt[N], h[N], d[N], tot;
struct node{int v, next, w;}e[N << 4];
inline void add(int u, int v, int w){e[++ tot] = (node){v, head[u], w}; head[u] = tot;}
inline int spfa(int s)
{
queue<int> q;
memset(vis, 0, sizeof vis);
for(int i = 1; i <= n; i ++) h[i] = INF;
h[s] = 0;
vis[s] = 1;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].v, w = e[i].w;
if(h[v] > h[u] + w)
{
h[v] = h[u] + w;
if(!vis[v])
{
vis[v] = 1;
cnt[v] ++;
q.push(v);
if(cnt[v] == n + 1) return 0;
}
}
}
}
return 1;
}
inline void dijkstra(int s)
{
priority_queue<pii, vector<pii>, greater<pii> > q;
memset(vis, 0, sizeof vis);
for(int i = 1; i <= n; i ++)d[i] = INF;
d[s] = 0;
q.push({0, s});
while(!q.empty())
{
int u = q.top().second;
q.pop();
if(vis[u]) continue ;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].v, w = e[i].w;
if(d[v] <= d[u] + w) continue;
d[v] = d[u] + w;
q.push({d[v], v});
}
}
return ;
}
signed main()
{
n = read(), m = read();
for(int i = 1; i <= n; i ++) add(0, i, 0);
for(int i = 1; i <= m; i ++)
{
int u = read(), v = read(), w = read();
add(u, v, w);
}
if(!spfa(0)) return cout << "-1" << endl, 0;//负环输出0
for(int u = 1; u <= n; u ++)
for(int i = head[u]; i; i = e[i].next)
e[i].w += h[u] - h[e[i].v];//修改边权
for(int i = 1; i <= n; i ++)
{
dijkstra(i);
int ans = 0;
for(int j = 1; j <= n; j ++)
{
if(d[j] == INF) ans += j * INF;
else ans += j * (d[j] + h[j] - h[i]);
}
cout << ans << endl;
}
return 0;
}
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/p/17740532.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2022-10-06 搜索学习笔记