学这个是为了支持在带负权值的图上跑 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. h5 在全屏iphonex中的适配

    iphonex 已经上线有一段时间了,作为业界刘海屏幕第一款机型,导致全屏不能正常的全屏显示了,,所以需要对iphonx 适配,下面就详细说说如何适配 先看一张适配前后的图: iphonex 提供的 ...

  2. css实现半圆效果

    效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  3. DOCTYPE(⽂档类型) 的作⽤

    DOCTYPE是HTML5中一种标准通用标记语言的文档类型声明,它的目的是告诉浏览器(解析器)应该以什么样(html或xhtml)的文档类型定义来解析文档,不同的渲染模式会影响浏览器对 CSS 代码甚 ...

  4. LC-1

    Two Sum Given an array of integers nums and an integer target, return indices of the two numbers suc ...

  5. 约定编程与Sping AOP

    一.约定编程 Spring AOP是一种约定流程的编程,咱们可以先通过动态代理模式的实现来理解Spring AOP的概念. 代理的逻辑很简单,例如,当你需要采访一名儿童时,首先需要经过他父母的同意,在 ...

  6. 2021.12.08 平衡树——FHQ Treap

    2021.12.08 平衡树--FHQ Treap http://www.yhzq-blog.cc/fhqtreapzongjie/ https://www.cnblogs.com/zwfymqz/p ...

  7. JVM内存管理面试常见问题全解

    目录 一.什么是JVM 1.jvm的三个组成部分 二.类加载系统 1.类的加载过程 2.类加载器 三.双亲委派机制 1.双亲委派机制介绍 2.为什么要双亲委派机制 3.双亲委派机制的核心源码 4.全盘 ...

  8. k8s入门之基础环境准备(一)

    一.在虚拟机中安装Ubuntu20.04.4系统 1.下载Ubuntu20.04.4服务器版本系统 下载链接地址如下: https://mirrors.tuna.tsinghua.edu.cn/ubu ...

  9. Apache Doris Oracle ODBC外表使用指南

    1.软件环境 操作系统:ubuntu 18.04 Apache Doris :0.15 Postgresql数据库:oracle 19c UnixODBC:2.3.4 Oracle ODBC :ins ...

  10. 使用aspnetcore前后端分离开发,你一定要知道这个

    前言 用过Vue单页面应用开发的,一定都知道Vue-router这个路由组件,它支持hash和history两种模式. HTML5 History 模式 vue-router 默认 hash 模式 - ...