引入1:單源最短路
如果沒有非負邊權,我們自然可以想到dij。但是如果有負邊權呢?這時候就要用spfa演算法求解。
原理&講解
用dis陣列記錄源點到有向圖上任意一點距離,其中源點到自身距離為0,到其他點距離為inf。將源點入隊,並重複以下步驟:
實際上我們可以將其理解為bfs
如果圖是隨機生成的,時間複雜度為 o(km) (k可以認為是個常數,m為邊數,n為點數)
但是實際上spfa的演算法複雜度是 o(nm) ,可以構造出卡spfa的資料,讓spfa超時。
在noi 2018的第一天第一題中,出題人卡了spfa演算法,導致100分變成60分,所以在沒有負環、單純求最短路徑,不建議使用spfa演算法,而是用dijkstra演算法。
在初一我們學到一條三角形中的性質,即同一三角形內兩邊之和大於第三邊。而最短路中如u->v的最短路它是小於等於其它任意路徑的,這使我們容易yy到三角形。也就是說,我們實際上每次都是在判斷這條路徑符不符合三角形不等式,若不符合,我們就將原先的路徑鬆弛為現在的路徑,使得現在的路徑滿足三角形不等式。但是為什麼鬆弛後要將終點入隊呢?spfa的過程是bfs,它是不停擴充套件節點的。而當我們更新了這一條路徑,那麼可能會出現基於這一條路徑的新路,我們需要判斷原路與新路是否滿足三角形不等式。
模擬&**
我們可以手推這張圖模擬一下~
我們以1為源點,初始化:dis[源點]=0,其他為正無窮,並將源點入隊。
隊首1出隊,並列舉它的出邊1->2,1->3。由dis[1]+w(1,2)=1
隊首2出隊,列舉它的出邊2->3,2->4,2->5。都不滿足三角形不等式,所以鬆弛它們。並將3,4,5入隊,但由於3已在隊內,所以不管。
隊首3出隊,沒有能鬆弛的邊,直接略過。
此時隊內剩下4,5,由於這兩點沒有出邊,所以在此不列舉。
手繪勿噴
下面是帶注釋**:
#include#include#include#include#include#include#include#include#define n 110000#define inf 0x3f3f3f3f
using namespace std;
int n,m,a,b,c,vis[n],dis[n];
struct node
;//定義乙個結構體來儲存每個入度點以及對應邊的權值
//比如邊u->v,權值為w,node結構體儲存的就是v以及w。
vectorv[n];
void spfa(int u);
int main()
spfa(1);
if(dis[n]!=inf)
printf("%d\n",dis[n]);
else
printf("impossible");
return 0;
}void spfa(int u);//定義乙個結構體來儲存每個入度點以及對應邊的權值
//比如邊u->v,權值為w,node結構體儲存的就是v以及w。
vectorv[n];
void spfa(int u);
int main()
memset(instack,0,sizeof(instack));
memset(dis,0,sizeof(dis));
flag=0;
for(int i=1;i<=n;i++)
if(flag)printf("yes");
else printf("no");
return 0;
}void spfa(int u)
instack[u]=true;
vectors=v[u];
for (int i = 0; i < s.size(); ++i)
}instack[u]=false;
}
最短路徑之spfa
其實就是用佇列對bellman ford進行優化 include include include include include include using namespace std static const int maxn 1000 點的數目 static const int inf 0x3f...
SPFA 最短路徑
給你乙個傳送門 粗略講講spfa演算法的原理,spfa演算法是1994年西安交通大學段凡丁提出 是一種求單源最短路的演算法 演算法中需要用到的主要變數 int n 表示n個點,從1到n標號 int s,t s為源點,t為終點 int d n d i 表示源點s到點i的最短路 int p n 記錄路徑...
最短路徑 之 SPFA演算法
求最短路徑的演算法有許多種,除了排序外,恐怕是oi界中解決同一類問題演算法最多的了。最熟悉的無疑是dijkstra,接著是bellman ford,它們都可以求出由乙個源點向其他各點的最短路徑 如果我們想要求出每一對頂點之間的最短路徑的話,還可以用floyd warshall。spfa是這篇日誌要寫...