其他分享
首页 > 其他分享> > Johnson 全源最短路

Johnson 全源最短路

作者:互联网

Johnson 全源最短路

Johnson 和 Floyd 一样,是一种能求出无负环图上任意两点间最短路径的算法。该算法在 1977 年由 Donald B. Johnson 提出。
Johnson 算法则通过另外一种方法来给每条边重新标注边权。
我们新建一个虚拟节点(在这里我们就设它的编号为0)。从这个点向其他所有点连一条边权为0的边。
接下来用SPFA算法求出从0号点到其他所有点的最短路,记为 dis
假如存在一条从点u到点v,边权为w的边,则我们将该边的边权重新设置为w += dis[u] - dis[v];
接下来以每个点为起点,跑 n轮 Dijkstra 算法即可求出任意两点间的最短路了。
最后加上dis[v] - dis[u];
容易看出,该算法的时间复杂度是O(nmlogm) 。

luogu P5905 Johnson 全源最短路

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 1000000000ll
using namespace std;
typedef long long ll;
const int N=2e4;
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N];
int head[N],cnt;
int n,m,u,v,w;
void add(int u,int v,int w)
{
     ++cnt;
     e[cnt].from = u;
     e[cnt].to = v;
     e[cnt].dis = w;
     e[cnt].next = head[u];
     head[u] = cnt;
}
int mapp[N];
int d[N];
int num[N];
bool vis[N];
queue<int> q;
bool SPFA(int u)
{
    memset(mapp,0x3f,sizeof(mapp));
    memset(vis,0,sizeof(vis));
    mapp[u] = 0; vis[u] = true;
    q.push(u);
    while(!q.empty())
    {
       int x = q.front();
       vis[x] = false;
       q.pop();
       for(int i=head[x];i;i=e[i].next)
       {
           int y = e[i].to;
           if(mapp[y] > mapp[x] + e[i].dis)
           {
               mapp[y] = mapp[x] + e[i].dis;
               if(vis[y] == false)
               {
                  vis[y] = true;
                  num[y]++;
                  q.push(y);
               }
               if(num[y] >= n + 1) return true;
           }
       }
    }
    return false;
}
struct node{
    int dis;
    int pos;
    bool operator <(const node &x)const
    {
        return x.dis < dis;
    }
};
priority_queue<node> Q;
void Dijkstra(int u)
{
     memset(d,0x3f,sizeof(d));
     memset(vis,0,sizeof(vis));
     d[u] = 0;
     Q.push((node){0,u});
     while(!Q.empty())
     {
         node p = Q.top();
         Q.pop();
         int x = p.pos;
         if(vis[x]) continue;
         vis[x] = 1;
         for(int i=head[x];i;i=e[i].next)
         {
             int y = e[i].to;
             if(d[y] > d[x] + e[i].dis)
             {
                d[y] = d[x] + e[i].dis;
                Q.push((node){d[y],y});
             }
         }
     }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    for(int i=1;i<=n;i++)
    add(n+1,i,0);
    bool flag = SPFA(n+1);
    if(flag == true) 
    {
        puts("-1");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=e[j].next)
        e[j].dis += mapp[i] - mapp[e[j].to];
    }
    for(int i=1;i<=n;i++)
    {
        Dijkstra(i);
        ll sum = 0;
        for(int j=1;j<=n;j++)
        {
            if(d[j] == 1061109567) 
            {
                sum += (ll)j*INF;
            }
            else sum += (ll)j*(d[j] + mapp[j] - mapp[i]);
            
        }
        printf("%lld\n",sum);
    }
    return 0;
}

标签:cnt,Johnson,int,全源,vis,mapp,短路,dis
来源: https://www.cnblogs.com/Elgina/p/15359297.html