noip快要考了發現spfa不會打的我決定來總結一下最短路演算法。
dijkstra基於最短路的最優子結構性質。設\(s(u, v)\)表示u到v的最短路,若k是它們最短路l上的點,那麼\(s(u, k)+s(k, v)=s(u, v)\)(首先\(s(u, k)+s(k, v)>=s(u, v)\),並且如果\(s(u, k)+s(k, v)>s(u, v)\),那麼u到v的最短路一定不經過k,畫個圖就明白了)。設源點為s,當前鬆弛點為p,則\(s(s, p)\)必定對於某乙個與p相鄰的節點q滿足\(s(s,p)=s(s,q)+s(q,p)\)成立。所以演算法就成立了(前提是沒有負權邊,不然曾經的點的最短路就不是真正的最短路, 而整個演算法是建立在求出所有點的正確的最短路上的)。注意dijkstra中,由於最多鬆馳m次,因此最多將堆中點的權值減去m次,用普通堆的複雜度是\(o(mlogm)=o(mlogn)\),而用斐波那契堆,可以擱置某些減權操作,使得鬆馳的總時間複雜度變成\(o(nlogn)\),不過我並不會0.0。
(貌似正確的)程式:
int dis[maxn*2], vis[maxn];
struct cmp
};priority_queue, cmp> q;
void dijkstra(int src){
memset(dis, 0x3f, sizeof(dis)); dis[src]=0;
int u, v; q.push(src);
for (int i=1; i<=n; ++i){ //出n個點
while (vis[u=q.top()]) q.pop(); vis[u]=1;
for (int j=fir[u]; j; j=e[j].nxt){
v=e[j].to;
if (dis[u]+e[j].v這樣寫是錯的!這種情況下stl無法正確維護優先佇列。所以必須要用\(greater+pair\)/\(struct\)。
不過為了更簡潔,就這樣吧……
首先要說明bellman-ford演算法的正確性。只要\(s(u, k)+s(k, v)>s(u, v)\)成立,那麼對所有結點都鬆弛n次,最短路就一定可以被求出來(最短路的長<=n)。spfa就是只考慮鬆弛後的結點的乙個玄學優化,至於為什麼對?!咳咳這是經驗公式
floyd的本質是動態規劃,至於為什麼把k放在外層,是因為k是動態規劃狀壓的狀態。若用\(f[k][i][j]\)表示可以通過1到k中結點的ij最短路路徑,\(f[k][i][j]=min(f[k-1][i][j], f[k-1][i][k]+f[k-1][k][j])\),而最外面一層空間被省略了,因為狀態裡面有k的通通不會更新。所以能保證正確性。
也可以從矩陣的角度來理解。考慮求點對之間走x步的方案數,其實相當於x個鄰接矩陣相乘。
如何證明呢?設現在的情況是走x步的矩陣x和鄰接矩陣y相乘。那麼x的第i行第j列,就表示從i到j的方案數。y的第i行第j列表示從i到j的連通性。那麼,新的從i到j的方案數,事實上就是選乙個點k多走一步的方案數。因此,x的第i行乘上y的第j列,表示的就是從i到k再到j的方案數。時間複雜度\(o(n^4)\)
由於floyd要求的是最短路,我們發現可以用矩陣快速冪優化到\(o(n^3\log n)\)!!!欸欸欸,floyd不是\(n^3\)的嘛……
這是因為floyd只乘了矩陣的第k行,乘了n次。
最短路徑演算法 最短路
在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?input 輸入包括多組資料。每組資料第一行是兩個整數n m n 100,m 10000 n...
最短路演算法
常用的最短路演算法有三種 disjkstra,floyd,ballman floyd 一 disjkstra演算法 dijkstra演算法要求圖上的權非負數。同樣使用於無向圖 html view plain copy include stdio.h hdu 2544 define maxsum 0x...
最短路演算法
最短路演算法有很多,具體哪個好,和資料是有很大關係的 從起點開始向外擴充套件,最壞o v e 實際體驗比o e log v 的dijkstra可能快 include include define max e 4002 define max v 1002 define inf 0x3f3f3f usi...