一下都假設該有向圖(無向圖同理)有n個點,m條邊。html
談及全源最短路,第一個想到的是弗洛伊德算法,簡單有效,由於並不是本篇文章重點,因此只是把代碼放在這裏:ios
int main(){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int q=1;q<=n;q++) if(d[j][p]>d[j][i]+d[i][q]) d[j][p]=d[j][i]+d[i][q]; }
惟一要注意的就是必需要枚舉轉折點。時間複雜度O(n^3)$,當n很大時不是一個能夠接受的數字。c++
或者跑n遍單元最短路。你能夠用spfa跑,這樣的時間複雜度爲\(O(n^2m)\)能夠處理負邊權。算法
順便一提,spfa時間複雜度稀疏圖約爲\(O(m*2)\),稠密圖\(O(m*INF)\)很大一個數數組
有dijkstra跑的話是\(O(n^2logn)\),加了堆優化,沒法處理負邊權。優化
能夠發現,以上三種狀況都不是全能的,且時間複雜度不夠優。因此咱們須要一個更有效的方法。spa
由於dijkstra是目前時間複雜度最優的,因此用dijkstra跑是最理想的,那麼咱們須要解決負邊權的問題。code
第一步:添加一個結點(結點0)向全部結點連一個邊權爲0的邊,從這個點跑一遍spfa,檢驗是否存在負環,同時獲得結點0到全部點的最短路,結點u對於結點0的最短路記爲\(h_u\),同時,把起點爲u終點爲v的邊的權值更新爲\(w_{u,v}+h_u-h_v\)。由於h數組存的是關於結點0的最短路,多有必定有\(h_v\le h_u+w_{u,v}\) 不然,不等號右邊必定能夠更新不等號左邊,與h數組的定義不符。因此,在作完後全部邊的權值變成了非負值,咱們能夠跑dijkstra。htm
那麼這麼作的正確性在哪裏?blog
s到t的路徑中隨便取出一條 \(𝑠−>𝑝1−>𝑝2−>⋯−>𝑝𝑘−>𝑡\)
則這條路徑長度爲 \((𝑤_{𝑠,𝑝1}+ℎ_𝑠−ℎ_{𝑝1})+(𝑤_{𝑝1,𝑝2}+ℎ_{𝑝1}−ℎ_{𝑝2})+⋯+(𝑤_{𝑝𝑘,t}+ℎ_{𝑝𝑘}−ℎ_𝑡)\)
化簡獲得 \(w_{s,p1}+w_{p1,p2}+...+w{pk,t}+h_s-h_t\)
對於從s到t的全部路徑,\(h_s,h_t\)是固定的,因此從s到t的最短路在進行了這個操做後最短路路徑不變。
第二步:跑dijkstra
第三步:輸出答案
記得必定要\(-h_s+h_t\)。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<sstream> #include<queue> #include<map> #include<vector> #include<set> #include<deque> #include<cstdlib> #include<ctime> #define dd double #define ll long long #define ull unsigned long long #define N 10000 #define M 3010 using namespace std; const ll INF=1e9; const ll IINF=0x3f3f3f3f; int n,m; struct edge{ int from,to,w,next; inline void intt(int from_,int to_,int w_,int next_){ from=from_;to=to_;w=w_;next=next_; } }; edge li[N]; int head[M],tail; inline void add(int from,int to,int w){ li[++tail].intt(from,to,w,head[from]); head[from]=tail; } ll h[M]; struct SPFA{ queue<int> q;bool vis[M]; int how_v[M]; inline bool spfa(int u){ while(!q.empty()) q.pop(); memset(h,IINF,sizeof(h)); memset(how_v,0,sizeof(how_v)); memset(vis,0,sizeof(vis)); h[u]=0;q.push(u);vis[u]=1; while(!q.empty()){ int top=q.front();q.pop(); // printf("%d\n",top); vis[top]=0; how_v[top]++;if(how_v[top]==n+1) return 0; // int k=head[top];printf("%d \n",top); for(int k=head[top];k;k=li[k].next){ int to=li[k].to; // printf("%d\n",h[to]); if(h[to]>h[top]+li[k].w){ h[to]=h[top]+li[k].w; if(!vis[to]){ q.push(to);vis[to]=1; } } } } return 1; } }; SPFA s; struct DIJ{ struct rode{ int sum; ll d; rode() {} rode(int sum,ll d) : sum(sum),d(d) {} }; struct cmp{ inline bool operator () (rode a,rode b){ return a.d>b.d; } }; priority_queue<rode,vector<rode>,cmp> q; bool vis[M];ll d[N]; inline void dij(int u){ memset(d,IINF,sizeof(d)); while(!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); d[u]=0;q.push(rode(u,d[u])); while(!q.empty()){ rode fr=q.top();q.pop(); if(vis[fr.sum]) continue; vis[fr.sum]=1; for(int k=head[fr.sum];k;k=li[k].next){ int to=li[k].to; if(d[to]>d[fr.sum]+li[k].w){ d[to]=d[fr.sum]+li[k].w; q.push(rode(to,d[to])); } } } } }; DIJ di; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int from,to,w; scanf("%d%d%d",&from,&to,&w); add(from,to,w); } for(int i=1;i<=n;i++) add(n+1,i,0); // for(int k=head[n+1];k;k=li[k].next) printf("%d ",li[k].to); if(!s.spfa(n+1)){ printf("-1"); return 0; } // for(int i=1;i<=n+1;i++) printf("%d ",s.how_v[i]); // while(1); for(int i=1;i<=m;i++) li[i].w+=h[li[i].from]-h[li[i].to]; for(int i=1;i<=n;i++){ di.dij(i); ull ans=0; for(int j=1;j<=n;j++){ if(di.d[j]>INF) ans+=INF*j; else ans+=(j*(di.d[j]+h[j]-h[i])); // printf("%lld ",di.d[j]); } // while(1); printf("%lld\n",ans); } return 0; }