Johnson

Johnson

Johnson算法是一种Donald B. Johnson在1977年发布的:在边加权有向图中找到所有顶点对之间最短路径的算法。

jonhnson允许某些边权重为负数,但不能是负环
通过使用Bellman-Ford 算法来计算输入图的转换,以消除所有负权重,从而允许在转换后的图上使用Dijkstra 算法。

Suurballe算法中也使用了类似的重加权技术,用于在具有非负边权重的图形中查找相同两个顶点之间最小总长度的两条不相交路径。

算法步骤

  1. 将新节点 q 添加到图中,通过零权重边连接到其他每个节点。
  2. 使用BellmanFord算法,从新的顶点 q 开始,为每个顶点 v 查找从 qv 的路径的最小权重 hv。如果此步骤检测到负环,则终止算法使w(u,v)+h(s)h(s)
    4 .使用BellmanFord计算的值重新加权原始图形的边缘:从uv的边,具有长度wuv,给出新的长度 wuv+huhv
    3 删除 q,并使用 Dijkstra 算法查找从每个节点s 到重新加权图中其他每个顶点的最短路径。然后计算原始图中每个距离Duv的距离,方法是将hvhu添加到Dijkstra算法返回的距离中。

正确性

节点st中之间的所有路径都添加了h(s)h(v),设pst路径,它在加权后的权重w由下表示

(w(s,p1)+h(s)h(p1))+(w(p1,p2)+h(p1)h(p2))++(w(pn,t)+h(pn)h(t))

每个wx中的 后一项 和wx+1前一项的消去

w(s,p1)+w(p1,p2)++w(pn,t)+h(s)h(t)

由于重新加权增加了相同的权重st,路径是原始加权图中的最短路径,当且仅当它是重新加权后的最短路径。属于从q到任何节点的最短路径的边缘的权重为0,因此在重新加权图中,从q到每个节点的最短路径的长度变为0;但是,它们仍然是最短的路径。因此,不可能有负边:如果边 uv 在重新加权后具有负权重,则从 qu 的零长度路径与此边一起将形成从 qv 的负权路径,这与所有顶点与q 的距离为零的事实相矛盾。负边的不存在确保了Dijkstra算法找到的路径的最优性。原始图中的距离可以通过加权变换,根据Dijkstra算法在重新加权图中计算的距离来计算。

#include <bits/stdc++.h>
using namespace std;
typedef  pair<int, int> pii;
const int N = 3e3 + 5;
int n, m, h[N], dis[N];
vector<pii> g[N];
int main() {
  cin >> n >> m;
  for(int w,u,v,i = 1; i <= m; i++)
   {
    cin >> u >> v >> w;
    g[u].push_back({v, w});
  }
  for(int i = 1; i <= n; i++) 
  {
    bool flag = 0;
    for(int j = 1; j <= n; j++)
      for(auto it : g[j])
        if(h[j] + it.second < h[it.first])
          flag = 1, h[it.first] = h[j] + it.second;
    if(i == n && flag) return !puts("-1");
  }
  for(int i = 1; i <= n; i++) 
  {
    long long ans = 0;
    for(int j = 1; j <= n; j++) dis[j] = i == j ? 0 : 1e9;
    priority_queue<pii, vector <pii>, greater <pii>> q;
    q.push({0, i});
    while(q.size()) 
    {
      auto t = q.top();q.pop();
      int id = t.second;
      if(t.first != dis[id]) continue;
      for(auto k : g[id]) 
      {
        int it = k.first, d = t.first + h[id] - h[it] + k.second;
        if(d < dis[it]) q.push({dis[it] = d, it});
      }
    }
    for(int j = 1; j <= n; j++) 
    ans += 1ll * j * (dis[j] + (dis[j] < 1e9 ? h[j] - h[i] : 0));
    cout << ans << endl;
  }
  return 0;
}

参考

初级图论
[johnson 维基百科](https://en.wikipedia.org/wiki/Johnson's_algorithm)

posted @   Erfu  阅读(353)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示