一步步學演算法 演算法分析 6 Floyd演算法

2021-06-18 12:12:28 字數 2972 閱讀 3511

floyd

演算法floyd演算法又稱為

弗洛伊德演算法

,插點法,是一種用於尋找給定的

加權圖中頂點間

最短路徑

的演算法。該

演算法名稱以創始人之一、2023年圖靈獎獲得者、史丹福大學電腦科學系教授

羅伯特·弗洛伊德

命名。正如我們所知道的,floyd演算法用於求最短路徑。floyd演算法可以說是warshall演算法的擴充套件,三個for迴圈就可以解決問題,所以它的時間複雜度為o(n^3)。

floyd演算法的基本思想如下:從任意節點a到任意節點b的最短路徑不外乎2種可能,1是直接從a到b,2是從a經過若干個節點x到b。所以,我們假設dis(ab)為節點a到節點b的最短路徑的距離,對於每乙個節點x,我們檢查dis(ax) + dis(xb) < dis(ab)是否成立,如果成立,證明從a到x再到b的路徑比a直接到b的路徑短,我們便設定dis(ab) = dis(ax) + dis(xb),這樣一來,當我們遍歷完所有節點x,dis(ab)中記錄的便是a到b的最短路徑的距離。

很簡單吧,**看起來可能像下面這樣:

for ( int i = 0; i < 節點個數; ++i )}}

}

但是這裡我們要注意迴圈的巢狀順序,如果把檢查所有節點x放在最內層,那麼結果將是不正確的,為什麼呢?因為這樣便過早的把i到j的最短路徑確定下來了,而當後面存在更短的路徑時,已經不再會更新了。

讓我們來看乙個例子,看下圖:

圖中紅色的數字代表邊的權重。如果我們在最內層檢查所有節點x,那麼對於a->b,我們只能發現一條路徑,就是a->b,路徑距離為9。而這顯然是不正確的,真實的最短路徑是a->d->c->b,路徑距離為6。造成錯誤的原因就是我們把檢查所有節點x放在最內層,造成過早的把a到b的最短路徑確定下來了,當確定a->b的最短路徑時dis(ac)尚未被計算。所以,我們需要改寫迴圈順序,如下:

for ( int k = 0; k < 節點個數; ++k )}}

}

這樣一來,對於每乙個節點x,我們都會把所有的i到j處理完畢後才繼續檢查下乙個節點。

那麼接下來的問題就是,我們如何找出最短路徑呢?這裡需要借助乙個輔助陣列path,它是這樣使用的:path(ab)的值如果為p,則表示a節點到b節點的最短路徑是a->...->p->b。這樣一來,假設我們要找a->b的最短路徑,那麼就依次查詢,假設path(ab)的值為p,那麼接著查詢path(ap),假設path(ap)的值為l,那麼接著查詢path(al),假設path(al)的值為a,則查詢結束,最短路徑為a->l->p->b。

那麼,如何填充path的值呢?很簡單,當我們發現dis(ax) + dis(xb) < dis(ab)成立時,就要把最短路徑改為a->...->x->...->b,而此時,path(xb)的值是已知的,所以,path(ab) = path(xb)。(path(xb) = y.  其中 x->...  ->y->b  所得的y也是path(ab) 的值  a->...->x->...->y->b)

好了,基本的介紹完成了,接下來就是實現的時候了,這裡我們使用圖以及鄰接矩陣:

#define infinite 1000           // 最大值

#define max_vertex_count 20   // 最大頂點個數//

struct graph

;//

首先,我們寫乙個方法,用於讀入圖的資料:

void readgraphdata( graph *_pgraph )}}

接著,就是核心的floyd演算法:

void floyd( int _arrdis[max_vertex_count], int _arrpath[max_vertex_count], int _nvertexcount )}//

for ( int k = 0; k < _nvertexcount; ++k )}}

}}

ok,最後是輸出結果資料**:

void printresult( int _arrdis[max_vertex_count], int _arrpath[max_vertex_count], int _nvertexcount )

else

while ( k != i );

//std::cout << stackvertices.top()+1;

stackvertices.pop();

unsigned int nlength = stackvertices.size();

for ( unsigned int nindex = 0; nindex < nlength; ++nindex )

std::cout << " -> " << j+1 << std::endl;}}}}}

好了,是時候測試了,我們用的圖如下:

測試**如下:

int main( void )

}floyd( arrdis, arrpath, mygraph.nvertexcount );

//printresult( arrdis, arrpath, mygraph.nvertexcount );

//system( "pause" );

return 0;

}

執行結果如下:

學習參考:  

一步步學演算法 演算法分析 6 Floyd演算法

floyd 演算法floyd演算法又稱為 弗洛伊德演算法 插點法,是一種用於尋找給定的 加權圖中頂點間 最短路徑 的演算法。該 演算法名稱以創始人之一 1978年圖靈獎獲得者 史丹福大學電腦科學系教授 羅伯特 弗洛伊德 命名。正如我們所知道的,floyd演算法用於求最短路徑。floyd演算法可以說是...

一步步學ROS

最近因為看svo的 裡面用到catkin決定要好好看ros,年前學會基本操作。啟動節點 rosrun package name executable name 檢視節點 rosnode list 注 rosout 節點是乙個特殊的節點,通過 roscore 自動啟動 檢視特定節點的資訊 rosnod...

一步步學彙編(九)call ret

一步步學彙編 九 call ret call和ret指令都是轉移指令,都修改ip,或同時修改cs和ip。經常被用來 實現子程式的設計。ret指令用棧中的資料,修改ip的內容,實現近轉移 retf指令用棧中的資料,修改cs和ip的內容,實現遠轉移 cpu執行ret指令時的操作 1 ip ss 16 s...