学这个是为了支持在带负权值的图上跑 Dijkstra.

为了这个我们要考虑把负的权值搞正。

那么先把我们先人已经得到的结论摆出来。我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体就是在原图的基础上建立超级源点。

然后我们把得到的这个东西称为 势能 \(h\) ,我们对于原图的每条边 \((u,v)\)的边权加上 \(h_u-h_v\),然后就可以跑 Dijkstra 了,求出的答案是 \(dis_{i,j}-h_i+h_j\).然后我们证明这样搞是对的。

首先需要证明这个搞法不会使求出来的值变化。

对于一条 \(i\) 到 \(j\) 的最短路径,有经过的点集 \(S\) ,那么我们求出的最短路是:

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)
\]

然后我们不难发现前后两项有部分可以抵消,所以有(设 \(d_{i,j}\) 为直接 Dijkstra 跑出的答案):

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)
\]
\[=d_{i,j}+h_1+h_n
\]

在加上势能满足三角形不等式:\(w(u,v)+h_u \geqslant h_v\)

就是差分约束(和最短路)那个东西啦。然后变形得到所有修改后边权大于0.

就没啦(-)

Johnson 全源最短路

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}
const ll INF=1e18;
const int N=3e3+3;
const int M=6e3+3;
int n,m;
struct Edge{
int v;ll w;
};
vector<int>head,nxt;
vector<Edge>to;
inline void join(int u,int v,int w){
nxt.push_back(head[u]);
head[u]=to.size();
to.push_back({v,w});
}
queue<int>q;
ll h[N];bool inq[N];
int hoop[N];
inline bool SPFA(int s){
while(!q.empty() ) q.pop();
for(int i=1;i<=n+1;++i){
h[i]=INF;inq[i]=0;hoop[i]=0;
}
inq[s]=1;q.push(s);h[s]=0;hoop[s]=1;
while(!q.empty() ){
int u=q.front();q.pop();inq[u]=0;
for(int i=head[u];~i;i=nxt[i]){
int v=to[i].v;ll w=to[i].w;
if(h[v]>h[u]+w){
h[v]=h[u]+w;
if(!inq[v]){
++hoop[v];
if(hoop[v]>n) return false;
q.push(v);
inq[v]=1;
}
}
}
}
return true;
}
ll dis[N][N];int S;
struct node{
int x;
inline friend bool operator <(node x,node y){
return dis[S][x.x]>dis[S][y.x];
}
};
namespace Dijkstra{
priority_queue<node>q;
inline void work(int s){
while(!q.empty() ) q.pop();
for(int i=1;i<=n;++i){
dis[s][i]=INF;
inq[i]=0;
}S=s;
inq[s]=1;q.push({s});dis[s][s]=0;
while(!q.empty() ){
int u=q.top().x;q.pop();inq[u]=0;
for(int i=head[u];~i;i=nxt[i]){
int v=to[i].v;ll w=to[i].w;
if(dis[s][v]>dis[s][u]+w){
dis[s][v]=dis[s][u]+w;
if(!inq[v]){
inq[v]=1;
q.push({v});
}
}
}
}
}
}
struct EDGE{
int u,v,w;
}e[M];
int main(){
//file(a);
n=read();m=read();
head.resize(n+1,-1);
for(int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
join(u,v,w);
e[i]={u,v,w};
}
for(int i=1;i<=n;++i){
join(0,i,0);
}
if(!SPFA(0)) {printf("-1\n");return 0;}
head.clear();
head.resize(n+1,-1);
to.clear();nxt.clear();
for(int i=1;i<=m;++i){
join(e[i].u,e[i].v,e[i].w+h[e[i].u]-h[e[i].v]);
}
for(int i=1;i<=n;++i){
Dijkstra::work(i);
}
for(int i=1;i<=n;++i){
ll ans=0;
for(int j=1;j<=n;++j){
if(dis[i][j]==INF) ans+=1ll*(1e9)*j;
else ans+=1ll*(dis[i][j]-h[i]+h[j])*j;
}
printf("%lld\n",ans);
}
return 0;
}

Johnson 全源最短路的更多相关文章

  1. 【学习笔记】 Johnson 全源最短路

    前置扯淡 一年多前学的最短路,当时就会了几个名词的拼写,啥也没想过 几个月之前,听说了"全源最短路"这个东西,当时也没说学一下,现在补一下(感觉实在是没啥用) 介绍 由于\(spf ...

  2. Johnson全源最短路

    例题:P5905 [模板]Johnson 全源最短路 首先考虑求全源最短路的几种方法: Floyd:时间复杂度\(O(n^3)\),可以处理负权边,但不能处理负环,而且速度很慢. Bellman-Fo ...

  3. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  4. Johnson 全源最短路径算法

    解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...

  5. 模板C++ 03图论算法 2最短路之全源最短路(Floyd)

    3.2最短路之全源最短路(Floyd) 这个算法用于求所有点对的最短距离.比调用n次SPFA的优点在于代码简单,时间复杂度为O(n^3).[无法计算含有负环的图] 依次扫描每一点(k),并以该点作为中 ...

  6. Johnson算法:多源最短路算法

    Johnson算法 请不要轻易点击标题 一个可以在有负边的图上使用的多源最短路算法 时间复杂度\(O(n \cdot m \cdot log \ m+n \cdot m)\) 空间复杂度\(O(n+m ...

  7. Floyd-Warshall 全源最短路径算法

    Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...

  8. 【算法】单源最短路——Dijkstra

    对于固定起点的最短路算法,我们称之为单源最短路算法.单源最短路算法很多,最常见的就是dijkstra算法. dijkstra主要用的是一种贪心的思想,就是说如果i...s...t...j是最短路,那么 ...

  9. 图论:Floyd-多源最短路、无向图最小环

    在最短路问题中,如果我们面对的是稠密图(十分稠密的那种,比如说全连接图),计算多源最短路的时候,Floyd算法才能充分发挥它的优势,彻彻底底打败SPFA和Dijkstra 在别的最短路问题中都不推荐使 ...

随机推荐

  1. SQL之总结(一)

    导游通项目之总结SQL 1.选择前面的某几个 oracle:  select * from tb_article where rownum<5 order by article_id       ...

  2. 小程序开发之一(使用fly进行http封装)

    原文地址:http://callmesoul.cn 下载fly js文件 fly小程序文档 /api/config.js 配置,主要配置全局的host url和request拦截和request拦截 ...

  3. 微信小程序版博客——开发汇总总结(附源码)

    花了点时间陆陆续续,拼拼凑凑将我的小程序版博客搭建完了,这里做个简单的分享和总结. 整体效果 对于博客来说功能页面不是很多,且有些限制于后端服务(基于ghost博客提供的服务),相关样式可以参考截图或 ...

  4. 【Android开发】URL 转义与反转义

    1,转义 @org.junit.Test public void testEncode(){ String url="http://192.168.0.19:8888/cas/login&q ...

  5. Checkstyle的安装与使用

    两种安装方法: 方法一: 1.Eclipse中,选择Help->Software Updates->Find and Install 2.选择 Search for new feature ...

  6. 在 Mac 上开发 .NET MAUI

    .NET 多平台应用程序 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用程序,这些应用程序可以从单个共享代码库在 Android.iOS.macO ...

  7. 掌握JavaScript中的迭代器和生成器,顺便了解一下async、await的原理

    掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 前言 相信很多人对迭代器和生成器都不陌生,当提到async和await的原理时,大部分人可能都知道async.aw ...

  8. 使用Socket实现HttpServer(二)

    使用Socket实现HttpServer(二) 前面我们使用 Socket 实现了一个简易的 HttpServer,接下来我们将对我们的服务器进行优化: 面向对象的封装 优化线程模型(引入多线程) R ...

  9. Problem N: 输出回字形

    这个题如果用for循环直接做的话恐怕得做上几个小时吧,加上一点小技巧,用坐标法来写这个题.就像下面这样: 坐标原点不在矩形的角上,而在矩形的中心处,这只是算是一个技巧,理解起来好理解而已.

  10. 数据库基础知识详解四:存储过程、视图、游标、SQL语句优化以及索引

    写在文章前:本系列文章用于博主自己归纳复习一些基础知识,同时也分享给可能需要的人,因为水平有限,肯定存在诸多不足以及技术性错误,请大佬们及时指正. 11.存储过程 ​ 存储过程是事先经过编译并存储在数 ...