Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记
如果你希望得到带互动的极简文字体验,请点这里
我们来学习johnson
Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法。它允许一些边权重为负数,但可能不存在负权重循环。它的工作原理是使用Bellman-Ford 算法来计算输入图的转换,该转换去除了所有负权重,从而允许在转换后的图上使用Dijkstra 算法。Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法。它允许一些边权重为负数,但可能不存在负权重循环。它的工作原理是使用Bellman-Ford 算法来计算输入图的转换,该转换去除了所有负权重,从而允许在转换后的图上使用Dijkstra 算法。
--维基百科
- 可以发现排序算法中最能够全源的只有Johnson 和 Floyd
最优情况:
全源最短路跑\(n\) 次 Bellman-Ford 算法解决,时间复杂度是\(O(n^2m)\),原始是Floyd的\(O(n^3)\)
我们可以更优,使用迪杰斯特拉\(O(nm \space logm)\)
但是我们还关注能否处理负边
所以只有SPFA,Floyd,贝尔曼,Johnson可以解决
原理解释
所以我们解决带负边的全源最短路时同时兼顾时间应该怎么做?
- 使用Dijkstra
但是Dijkstra不能处理有负边的问题,所以我们可以使边变为正数,我们基本得到3个猜想:
- 对每条边进行相同的增量,使所有边非负。
- 改变图的结构,不改变图的性质,使Dijkstra可做。
- 对每条边单独设计增量,使图的性质保证并且全图非负。
可以看出只有第三种是正确的。
为什么第一种不正确?
如上图(箭头错,1->3应该是3->1)3->2的最短路原本是-2(走上面),但是对于边权+5的图(绿)就成了9(走下面),路径发生了改变,不可取。
Johnson算法核心
建一个超级源,到所有点连0 权边,对超级源跑一遍SPFA,求出每个点的dis 值。重构原图边权,对于边 , , ,将其边权修改为 + dis − dis 。
由三角不等式: + dis ≥ dis ,从而新的边权一定是非负数。
在新图上跑全源 Dijkstra,以 \(u_0\) 为起点,假设经过 \(u_1\), \(u_2\), … , \(u_{t-1}\) 到达 \(u_t\) 。
则经过的边权分别为 $w_{12} $ \(-dis u_2 + w_{2,3}\) $ + dis u_2 − dis u_3 + ⋯ + $ $w_{t−1},t + dis u_{t−1} -dis u_t $
\]
只需将跑出的最短路结果做 \(− (dis u_1 − dis u_t )\) 变换就可以得到真实最短路。
正确性
为什么我们使用这个方法是正确的
在重新加权的图中,节点对s和t之间的所有路径都添加了相同的数量\(h ( s ) - h ( t )\)。
正确当且仅当重新加权后的最短路径是原始的最短路径。
\(dis_v \ge dis_u+e_w\)因此,不可能有负边:如果边 \(u \to v\) 在重新加权后具有负权重,那么从 \(q \to u\) 的零长度路径与这条边将形成从 \(q \to v\) 的负长度路径,这与以下事实相矛盾所有顶点到 \(q\) 的距离为零。
负边的不存在确保了 Dijkstra 算法找到的路径的最优性。
原始图中的距离可以通过逆重加权变换从重加权图中的Dijkstra算法计算出的距离计算出来。
Johnson 算法的前三个阶段如下图所示
图中左侧的图形有两个负边,但没有负循环。
中心图显示了新的顶点 \(q\) ,一个最短路径树,由 Bellman-Ford 算法计算,\(q\) 作为起始顶点,每个其他节点计算的值 \(h ( v )\) 作为从 \(q\) 到该节点的最短路径的长度节点。
请注意,这些值都是非正数,因为q到每个顶点都有一条长度为零的边,并且最短路径不能长于该边。
右侧显示了重新加权的图,通过替换每个边的权重形成 \({\displaystyle w(u,v)}{\displaystyle w(u,v)}\) 由 \(w ( u , v ) + h ( u ) − h ( v )\)。
在这个重新加权的图中,所有边的权重都是非负的,但任意两个节点之间的最短路径使用与原始图中相同两个节点之间的最短路径相同的边序列。该算法最后将 Dijkstra 算法应用于重新加权图中的四个起始节点中的每一个。
#include<bits/stdc++.h>
#define ll long long
#define fd(i, a, b) for (ll i = a; i >= b; i--)
#define r(i, a) for (ll i = fir[a]; i; i = e[i].nex)
#define file(a) freopen(#a ".in", "r", stdin);
#define il inline
#define gc getchar()
#define f(i,a,b) for(ll i=a;i<=b;i++)
using namespace std;
const ll maxn=3e5+10,INF=1e16;
il ll read(){
ll x=0,f=1;char ch=gc;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc;}
while(ch>='0'&&ch<='9') x=(x*10)+(ch^48),ch=gc;
return x*f;
}
ll fir[maxn],n,m,cnt;
struct edge{ll to,nex,w;}e[maxn<<1];
il void add(ll a,ll b,ll c){e[++cnt].to=b,e[cnt].w=c,e[cnt].nex=fir[a];fir[a]=cnt;}
bool vis[maxn];
ll far[maxn];
ll num[maxn];
il bool spfa(ll x){
queue<ll> q;
memset(far,0x7f,sizeof(far));
far[x]=0;
q.push(x);
while(!q.empty()){
ll u=q.front();
// cout<<far[u]<<endl;
// cout<<u<<endl;
vis[u]=0;
if(++num[u]>n) return 0;
q.pop();
r(i,u){
ll v=e[i].to;
// cout<<e[i].w<<endl;
if(far[v]>far[u]+e[i].w){
far[v]=far[u]+e[i].w;
// cout<<far[v]<<endl;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return 1;
}
priority_queue<pair<ll,ll> >q;
ll dis[maxn],cop;
il void dijkstra(ll x){
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
cop=dis[0];
dis[x]=0;
q.push(make_pair(0,x));
while(!q.empty()){
ll u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
r(i,u){
ll v=e[i].to;
// cout<<e[i].w<<endl;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push(make_pair(-dis[v],v));
}
}
}
}
ll Add=1e9;
int main()
{
n=read(),m=read();
f(i,1,m){
ll x=read(),y=read(),z=read();
add(x,y,z);
}
f(i,1,n) add(0,i,0);
// cout<<1;
if(spfa(0)){
f(i,1,n) r(j,i){
// cout<<far[i]-far[e[j].to]<<endl;
e[j].w+=far[i]-far[e[j].to];
// cout<<e[j].w<<endl;
}
// f(i,1,n) cout<<far[i]<<" ";
// cout<<endl;
f(i,1,n){
ll ans=0;
dijkstra(i);
f(j,1,n){
if(dis[j]==cop) ans+=j*Add;
else ans+=j*(dis[j]+far[j]-far[i]);
}
printf("%lld\n",ans);
}
}
else printf("-1");
}
参考文献
1.Johnson's algorithm--wikipedia
Johnson 全源最短路径算法学习笔记的更多相关文章
- Johnson 全源最短路径算法
解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...
- Floyd-Warshall 全源最短路径算法
Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...
- 【学习笔记】 Johnson 全源最短路
前置扯淡 一年多前学的最短路,当时就会了几个名词的拼写,啥也没想过 几个月之前,听说了"全源最短路"这个东西,当时也没说学一下,现在补一下(感觉实在是没啥用) 介绍 由于\(spf ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- Johnson全源最短路
例题:P5905 [模板]Johnson 全源最短路 首先考虑求全源最短路的几种方法: Floyd:时间复杂度\(O(n^3)\),可以处理负权边,但不能处理负环,而且速度很慢. Bellman-Fo ...
- Johnson 全源最短路
学这个是为了支持在带负权值的图上跑 Dijkstra. 为了这个我们要考虑把负的权值搞正. 那么先把我们先人已经得到的结论摆出来.我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体 ...
- Dijkstra 单源最短路径算法
Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年 ...
- Bellman-Ford 单源最短路径算法
Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...
随机推荐
- Ubuntu 16.04 NVidia显卡 输入密码后 重复出现登录界面
问题根源:显卡驱动 解决办法: CTRL+ALT+F1 # 切换到命令行 sudo service lightdm stop # 关闭桌面显示管理器 sudo apt-get remove --pu ...
- 移动端 uni-app 滑动事件 精确判断手指滑动方向
移动端根据手指滑动操作判断滑动方向 设计思路: 1.根据移动端touchstart和touchend方法获取手指触摸屏幕的开始坐标和结束坐标 2.根据两个坐标计算与水平方向的夹角 3.根据夹角判断当前 ...
- 【Spring 持久层】Spring 与 Mybatis 整合
持久层整合总述 1.Spring 框架为什么要与持久层技术进行整合? JavaEE开发需要持久层进行数据库的访问操作 JDBC.Hibernate.MyBatis 进行持久开发过程存在大量的代码冗余 ...
- linux常用查询命令
1 **系统** 2 # uname -a # 查看内核/操作系统/CPU信息 3 # head -n 1 /etc/issue # 查看操作系统版本 4 # cat /proc/cpuinfo # ...
- 八、Abp vNext 基础篇丨标签聚合功能
介绍 本章节先来把上一章漏掉的上传文件处理下,然后实现Tag功能. 上传文件 上传文件其实不含在任何一个聚合中,它属于一个独立的辅助性功能,先把抽象接口定义一下,在Bcvp.Blog.Core.App ...
- Identity角色管理四(删除角色)
角色删除方法 [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> Delete(string id) ...
- 通过HttpURLConnection下载图片到本地--下载附件
一.背景说明 现在我做的系统中,需要有一个下载附件的功能,其实就是下载图片到本地中.相应的图片保存在多媒体系统中,我们只能拿到它的资源地址(url),而不是真实的文件. 这里记录的是下载单个图片.下篇 ...
- 马哈鱼数据血缘分析器分析case-when语句
马哈鱼数据血缘分析器是一个分析数据血缘关系的平台,可以在线直接递交 SQL 语句进行分析,也可以选择连接指定数据库获取 metadata.从本地上传文件目录.或从指定 git 仓库获取脚本进行分析. ...
- # Zombie Gunship Survival(僵尸炮艇生存)GG修改器修改教程
Zombie Gunship Survival(僵尸炮艇生存)GG修改器修改教程 1.修改伤害,打击范围,武器冷却时间,子弹容量 测试手机机型:华为畅享7 系统版本:Android7.0 是否ROOT ...
- 【Python】python 2.7.16 x64 百度网盘
倒霉官网下载太慢,下好了分享出来,也给自己留一个备份. 链接:点这里提取码:znaf PS: py2.7版本 for win 64位