最短路算法主要有以下几个:
一 Dijkstra
二 Bellman-Ford
三 SPFA
四 ASP
五 Floyd-Warshall
首先约定一下图的表示:
struct Edge{
int
from,to,wt;
};
vector<int>G[N];
vector<Edge>G[N];
-------------Dijkstra算法
使用条件:无负权边
复杂度O:((V+E)*log(V))
下面是用优先队列实现的Dijkstra算法
//Dijkstra 优先队列版
#include<iostream>
#include<iomanip>
#include<cstring>
#include<stdio.h>
#include<map>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<fstream>
#include<queue>
#define rep(i,n) for(int i=0;i<n;i++)
#define fab(i,a,b) for(int i=(a);i<=(b);i++)
#define fba(i,b,a) for(int i=(b);i>=(a);i--)
#define MP make_pair
#define PB push_back
#define cls(x) memset(x,0,sizeof(x))
const int INF=0x7ffffff;
using namespace std;
const int N=1005;
struct Edge{
int from,to,w;
}edges[N];
vector<Edge>G[N];
typedef pair<int,int>PII;int d[N];
void Dijkstra(int s){
priority_queue<PII,vector<PII>,greater<PII> >Q;
fill(d,d+N,INF);
d[s]=0;
Q.push(MP(d[s],s));
while(!Q.empty()){
PII cur=Q.top();Q.pop();
int u=cur.second;
if(cur.first!=u)continue;
rep(i,G[u].size()){
int to=G[u][i].to;
int w=G[u][i].w;
if(d[to]>d[u]+w){
d[to]=d[u]+w;
Q.push(MP(d[to],to));
}
}
}
}
-------Bellman-Ford 算法
//Bellman-Ford 可判断负权环
//复杂度O(VE)
int n;// number of node
int m;// number of edge
bool Bellman_Ford(int s){
fill(d,d+N,INF);
d[s]=0;
rep(i,n){
bool update=0;
rep(j,m){
Edge &e=edges[j];
if(d[e.to]>d[e.from]+e.w){
d[e.to]=d[e.from]+e.w;
update=1;
}
}
if(!update)return true;
if(i==n-1&&update)return false;
}
}
------SPFA算法
spfa是对bellman算法的改进,改进了bellman盲目更新的顺序,用类似于dijkstra的队列来更新节点。
基本流程:开始节点s队列,对s的每一个邻接点v更新,如果v不在队列则进队,直到队列为空。如何判断负环呢?因为最短路最多包含V-1条边,因此每一个节点(包括源点s)最多入队V次,所以如果有节点入队V+1次,说明存在负环。
//SPFA 复杂度...据说是O(KE) k<<V
bool inqueue[N];
int cnt[N]={0};
bool SPFA(int s){
queue<int>Q;
cls(inqueue);
cls(cnt);
fill(d,d+N,INF);
d[s]=0;
Q.push(s);
inqueue[s]=1;
while(!Q.empty()){
int u=Q.front();Q.pop();
inqueue[u]=0;
rep(i,G[u].size()){
int to=G[u][i].to;
int w=G[u][i].w;
if(d[to]>d[u]+w){
d[to]=d[u]+w;
if(!inqueue[to]){
Q.push(to);
inqueue[to]=1;
if(++cnt[to]>n)return false;
}
}
}
}
return true;
}
------ASP算法
asp算法适用范围小,只能用于有向无环图,思想是dp,按拓扑序列更新节点复杂度O(N)
//asp复杂度O(N) 无环
int ind[N];
void ASP(int s){
cls(ind);
fill(d,d+N,INF);
queue<int>Q;
Q.push(s);
rep(i,m)++ind[edges[i].to];
rep(i,n)if(ind[i]==0)Q.push(i);
d[s]=0;
while(!Q.empty()){
int u=Q.front();Q.pop();
rep(i,G[u].size()){
int to=G[u][i].to;
int w=G[u][i].w;
if(d[to]>d[u]+w){
d[to]+d[u]+w;
}
if(--ind[to]==0)Q.push(to);
}
}
}
-----Floyd-Wallshall 多源最短路
//多源最短路径 Floyd-Warshall O(N^3)
int d[N][N];
void Floyd_Wallshall(){
rep(k,n){
rep(i,n){
rep(j,n){
if(d[i][j]>d[i][k]+d[k][j]){
d[i][j]=d[i][k]+d[k][j];
}
}
}
}
}