Floyed演算法學習

2021-07-11 13:20:10 字數 4400 閱讀 3785

正如我們所知道的,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(inti = 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(intk = 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)。

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

#define infinite 1000           // 最大值

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

//

structgraph

;

//

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

voidreadgraphdata( graph *_pgraph )

}

}

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

voidfloyd(int_arrdis[max_vertex_count],int_arrpath[max_vertex_count],int_nvertexcount )

}

//

for(intk = 0; k < _nvertexcount; ++k )

}

}

}

}

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

voidprintresult(int_arrdis[max_vertex_count],int_arrpath[max_vertex_count],int_nvertexcount )

else

while( k != i );

//

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

stackvertices.pop();

unsignedintnlength = stackvertices.size();

for( unsignedintnindex = 0; nindex < nlength; ++nindex )

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

}

}

}

}

}

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

測試**如下:

intmain(void)

}

floyd( arrdis, arrpath, mygraph.nvertexcount );

//

printresult( arrdis, arrpath, mygraph.nvertexcount );

//

system("pause");

return0;

}

如圖:

演算法學習 Union Find演算法

union find演算法有它的實際用途。多用於動態連通的應用場景。union find演算法是 給出兩個節點,判斷它們是否連通,如果連通,是不需要給出具體的路徑的 舉兩個例子作為主要表現 1 在網路連線中,當發現沒有連線的兩個節點,可以把他們連線起來,一旦節點都連線起來,又能把多餘的線拆除,這時候...

演算法學習 KM演算法

km演算法 用於求二分圖的最佳完美匹配 即權值最大的完美匹配 如果你也是個剛來學習km演算法的人 大概的用途肯定還是知道的吧 還是直接說重點吧 首先 理解km演算法前 必須有以下3個概念 1.可行頂標 對於乙個賦值二分圖g x,y,e,w x,y 代表二分圖的兩邊頂點標號 e代表邊 w代表邊的權值 ...

演算法 演算法學習01

貪婪 可以理解為最簡單基礎的求解方式,特點是 短視性 從這個特點入手很容易理解每一步取其最優的原理。雖然最終結果不一定是最好的,但是一定是較好的而且是最簡便的。因此在不過分追求最優結果或者對速度的要求高於結果的情況下,貪婪是不錯的選擇。分治可以理解為大事化小小事好搞,與貪婪的每一步的 串聯 不同,分...