SPFA 算法是 Bellman-Ford算法 的隊列優化算法的別稱,一般用於求含負權邊的單源最短路徑,以及判負權環。SPFA 最壞狀況下複雜度和樸素 Bellman-Ford 相同,爲 O(VE),可是通常狀況下他的複雜度仍是很優秀的,爲O(mn),其中稀疏圖中m約等於2,稠密圖...關於SPFA:他死了,n爲邊數(值得一提,有的很是bt的數據會故意卡spfa不讓你過 好比菊花圖,蒲公英圖什麼的)ios
算法大意:設立一個隊列來保存全部待優化的結點,先初始化全部最短路徑,而後從起點開始不斷遍歷每一條邊,不斷進行鬆弛操做,再用已經優化完的結點去更新隊列中其餘節點算法
重要變量解釋:優化
dis表示從源點到點i的最短路徑
vis表示這個點目前是否在隊列裏
head表示這個點全部出邊中序號最大的那一條spa
代碼:code
#include<cstdio> #include<iostream> #include<cstdlib> #include<iomanip> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<time.h> #include<queue> using namespace std; typedef long long ll; typedef long double ld; typedef pair<int,int> pr; const double pi=acos(-1); #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define Rep(i,u) for(int i=head[u];i;i=next[i]) #define clr(a) memset(a,0,sizeof a) #define pb push_back #define mp make_pair #define fi first #define sc second ld eps=1e-9; ll pp=1000000007; ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} ll read(){ ll ans=0; char last=' ',ch=getchar(); while(ch<'0' || ch>'9')last=ch,ch=getchar(); while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); if(last=='-')ans=-ans; return ans; } //head const int inf=2147483647; int n,m,s;//點的個數、有向邊的個數、出發點的編號 int dis[10005],vis[10005],head[10005],cnt; //dis表示從源點到點i的最短路徑 //vis表示這個點目前是否在隊列裏 //head表示這個點全部出邊中序號最大的那一條 struct Edge { int next,dis,to; }edge[9999999]; queue <int> q; inline void add_edge(int from,int to,int dis) { cnt++; edge[cnt].next=head[from]; edge[cnt].to=to; edge[cnt].dis=dis; head[from]=cnt; }//存邊 void spfa() { rep(i,1,n) dis[i]=inf,vis[i]=0;//初始化 dis[s]=0; vis[s]=1;//把始點標記成在隊列中 q.push(s);//入隊 while(!q.empty()) { int u=q.front();//隊首的點 q.pop();//出隊 vis[u]=0;//標記成已經出隊 for(int i=head[u];i;i=edge[i].next)//遍歷每一條邊 { int v=edge[i].to; if(dis[v]>dis[u]+edge[i].dis) { dis[v]=dis[u]+edge[i].dis;//鬆弛操做 if(!vis[v]) { q.push(v); vis[v]=1; }//入隊 } } } } int main() { scanf("%d %d %d",&n,&m,&s); for(int i=1;i<=m;++i) { int u,v,d;//第i條有向邊的出發點、目標點和長度 scanf("%d %d %d",&u,&v,&d); add_edge(u,v,d); } spfa(); for(int i=1;i<=n;++i) { if(i==s) printf("0 ");//本身到本身爲0 else printf("%d ",dis[i]); } return 0; }
感受和Dijkstra差很少,但其實他倆區別仍是很大的blog
Dijkstra是找到從當前節點全部出邊中找到最短的,而後用這條最短邊繼續更新其餘路徑隊列
而SPFA是對當前節點的全部出邊不斷進行鬆弛操做,而後用更新完的邊去更新其餘結點的其餘邊ip
(其實好像挺像的)get