關於最短路

2021-09-05 07:14:36 字數 1672 閱讀 2931

模板:

void dij()

p.push(make_pair(d[1],1));

while(!p.empty())

}}

}}

為啥想到用最小堆?因為每次都是找與源點最近的,vis為0的點,想到了用優先佇列找的快一點細節:d陣列用pair形式表示,pair的first是距離,second是點的下標。pair跟結構體差不多,如果用結構體寫就是

struct xx

d[maxn];

之前想過乙個問題,就是既然乙個點出棧了,那麼他就不可能再進棧了,因為出棧的前提是他已經被選為當前離源點最近的點,經過鬆弛操作之後又出棧,既然他已經是最近了,也就不會有別的點來鬆弛他,那麼他就不會再進棧了,也就是說乙個點只進棧一次,那麼為啥還需要用vis判斷呢?問題出在:程式是一旦乙個點被其他點鬆弛,它就進棧,為啥呢?因為說不定此時他就變成了離源點最近的點,它要跟其他的點競爭啊。。但是問題就是,這個點被多次鬆弛多次進棧但是每次都沒輪到他出棧。如圖:

如果兩個點之間是不去重的有向邊的話,即a->b跟b->a不一樣時,我覺得不能用鏈式向前星。。因為它是以某個點為起點,與之相連線的邊是誰誰誰,但是我不沒辦法知道以某個點為終點的邊都是誰。。。並且,遇到去重問題貌似也不能解決。反正光用最小堆優化就完事了,已經很快了。

bf演算法與dij區別:

dij不能有負權邊,因為dij是貪心,他只能找出來當前離源點最近的,卻不會想以後會不會有負權邊來更新當前最近的邊,比如:

為啥dij不能有負邊

它會把dis[b]確定為1,而實際上經過c->b,dis[b]= -8,這都是因為貪心造成的。而bf無所謂,因為他是擴散型的,下文會說。

這個遍歷為啥是v-1次,別的部落格沒見乙個說為啥的,我想了兩天,終於有個比較不錯的理解

從第一次開始,用與源點直接相連的邊(一條邊直接相連,就叫它親密度為1吧)來鬆弛與源點直接連線的點到源點的距離,然後更新了這些點的dis

第二次,只有親密度為1的邊使用過了,親密度為2的邊才有用武之地,比如說a->b->c,顯然只有b點的dis【】從無窮變成權值,b->c才有用處,不然dis[b]存的是無窮,那肯定不能借助b->c這條邊來鬆弛啊。

第三次,…………

那麼假如說這個圖是乙個長串,有v個點,那麼第v個點與源點的親密度就是v-1(中間隔了v-1條邊),也就是其他文章裡說到的為啥是頂多迴圈v-1次就能求出最短路徑。

實際執行時bf採取的是暴力,他實際上這v-1次每次都遍歷所有的邊,而他應該只遍歷與他親密度為v-1的邊就行了,做了嫩(俺是河南人)多的無用功,

比如第一次迴圈,它只能鬆弛與源點直接相連的邊,而他卻把所有邊都遍歷了一遍,浪費時間...

為了解決這個問題,可以用spfa,哪個點被更新了,再去更新與這個點相連的點的dis,犯不著每次都遍歷所有的邊。

鏈式向前星

待續……

關於最短路

把最近做的幾道最短路一起總結一下吧 poj1062 中文題,不解釋題意,對於渣渣來說,是先看別人題解後才做的,以酋長的允諾作為目標點,每乙個物品與替換物之間會有一條邊,由於交換有限制,所以建完圖後,以每乙個點為終點或是說最高點,先遍歷一次,把不能交換或間接交換的點去掉,然後再進行最短路尋找。實際就是...

關於最短路 1

我們可以把邊帶有權值的圖稱為帶權圖。邊的權值可以理解為兩點之間的距離。一張圖任意兩點間會有不同的路徑相連。最短路徑就是指連線兩點的這些路徑中最短的一條。我們有四種方法求出兩個點間最短的路徑 分別是floyed warshall演算法 簡稱floyed演算法 dijkstra演算法 bellman f...

最短路 最短路徑問題

題目描述 平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中的一些點之間有連線。若有連線,則表示可從乙個點到達另乙個點,即兩點間有通路,通路的距離為兩點直線的距離。現在的任務是找出從一點到另一點之間的最短路徑。input 共有n m 3行,其中 第一行為乙個整數n。第2行...