SPFA演算法 最短路徑

2021-07-02 00:40:13 字數 1991 閱讀 9807

只要最短路徑存在,spfa演算法必定能求出最小值,spfa對bellman-ford演算法優化的關鍵之處在於意識到:只有那些在前一遍鬆弛中改變了距離估計值的點,才可能引起他們的鄰接點的距離估計值的改變。為什麼隊列為空就不改變了呢?就是因為要到下一點必須經過它的前乙個鄰接點。。spfa可以處理負權邊。很多時候,給定的圖存在負權邊,這時類似dijkstra等演算法便沒有了用武之地,而bellman-ford演算法的複雜度又過高,spfa演算法便派上用場了。簡潔起見,我們約定有向加權圖g不存在負權迴路,即最短路徑一定存在。當然,我們可以在執行該演算法前做一次拓撲排序,以判斷是否存在負權迴路。

初始化: dis陣列全部賦值為inf(無窮大,不能是map[s][i]),path陣列全部賦值為s(即源點),或者賦值為-1,表示還沒有知道前驅,然後dis[s]=0;  表示源點不用求最短路徑,或者說最短路就是0。將源點入隊;另外記住在整個演算法中有頂點入隊了要記得標記vis陣列,有頂點出隊了記得消除那個標記(可能多次入隊)。

核心:讀取隊頭頂點u,並將隊頭頂點u出隊(記得消除標記);將與點u相連的所有點v進行鬆弛操作,如果能更新估計值(即令d[v]變小),那麼就更新,另外,如果點v沒有在佇列中,那麼要將點v入隊(記得標記),如果已經在佇列中了,那麼就不用入隊以此迴圈,直到隊空為止就完成了單源最短路的求解。

判斷有無負環:如果某個點進入佇列的次數超過n次則存在負環(spfa無法處理帶負環的圖),假設這個節點的入度是k(無向權則就是這個節點的連線的邊)如果進入這個佇列超過k,說明必然有某個邊重複了,即成環;換一種思路:用dfs,假設存在負環a1->a2->…->an->a1。那麼當從a1深搜下去時又遇到了a1,那麼直接可以判斷負環了所有用。當某個節點n次進入佇列,則存在負環,此時時間複雜度為o(n*m),n為節點,m為邊。

spfa演算法有兩個優化演算法 slf 和 lll: slf:small label first 策略,設要加入的節點是j,隊首元素為i,若dist(j)x則將i插入到隊尾,查詢下一元素,直到找到某一i使得dist(i)<=x,則將i出對進行鬆弛操作。 slf 可使速度提高 15 ~ 20%;slf + lll 可提高約 50%。 在實際的應用中spfa的演算法時間效率不是很穩定,為了避免最壞情況的出現,通常使用效率更加穩定的dijkstra演算法。個人覺得lll優化每次要求平均值,不太好,為了簡單,我們可以之間用c++stl裡面的優先佇列來進行slf優化。

#include #include #include #include using namespace std;

const int maxn=100;

const int inf=0x7fffffff;

struct edge;

vectoradjmap[maxn];//鄰接表

bool in_queue[maxn];//頂點是否在佇列中

int in_sum[maxn];//頂點入隊次數

int dist[maxn];//源點到各點的最短路徑

int path[maxn];//儲存到達i的前乙個頂點

int nodesum;//頂點數

int edgesum;//邊數

bool spfa(int source)

dq.push_back(source);

in_sum[source]++;

dist[source]=0;

in_queue[source]=true;

//初始化完成

while(!dq.empty())

else dq.push_back(to);}}

}}

return true;}

void print_path(int x)

cout<<"頂點1到頂點"<>nodesum>>edgesum;

for(i=1;i<=nodesum;i++)

adjmap[i].clear();//清空鄰接表

for(i=1;i<=edgesum;i++)

if(spfa(1))

else cout<<"圖中存在負權迴路"

}

最短路徑演算法 SPFA

求最短路徑的演算法有許多種,除了排序外,恐怕是oi界中解決同一類問題演算法最多的了。最熟悉的無疑是dijkstra,接著是bellman ford,它們都可以求出由乙個源點向其他各點的最短路徑 如果我們想要求出每一對頂點之間的最短路徑的話,還可以用floyd warshall。spfa是這篇日誌要寫...

SPFA演算法 最短路徑

spfa是一種求單源最短路的演算法 演算法中需要用到的主要變數 int n 表示n個點,從1到n標號 int s,t s為源點,t為終點 int d n d i 表示源點s到點i的最短路 int p n 記錄路徑 或者說記錄前驅 queue q 乙個佇列,用stl實現,當然可有手打佇列,無所謂 bo...

SPFA演算法 最短路徑

spfa演算法 最短路徑 粗略講講spfa 演算法的原理,spfa演算法是1994年西安交通大學段凡丁提出 是一種求單源最短路的演算法 演算法中需要用到的主要變數 int n 表示n個點,從1到n標號 int s,t s為源點,t為終點 int d n d i 表示源點s到點i的最短路 int p ...