最短路演算法

2022-08-28 14:15:28 字數 4280 閱讀 5568

最短路演算法

今天,我們來總結圖的最短路演算法,它的基礎演算法如下:

part1:單源最短路

一、dijkstra演算法。

1核心思想:貪心演算法=>每次找最短的邊,標記該點並對其餘未標記點鬆弛。

2模板:

void

dijkstra()

//ans為dis[k]

}

時間複雜度:o(n2)

3優化:找最短邊的時候可採用大根堆(優先佇列實現) 時間複雜度o(m+nlogn),**如下:

int

n,m,s,u,v,w,dis[n];

bool

vis[n];

vector

int,int> >g[n];

pair

t;priority_queue

int,int> >q;

intmain()}}

}

注意:為適應優先佇列(小根堆),pair第一維是邊(帶負號,使之彈出邊最小的),第二維是點。

ps:dijistra 不適用於負邊權(貪心失效)

二、bellman ford演算法

1核心思想:動規f[i][j][k]=> i->j 經歷k步的min;

2轉移方程:f[i][j]=min(f[i][j],f[i][k]+way(k->j) (k是某點,第三維省略)

3原理:乙個圖的最短路最多更新n-1次;

4空間複雜度o(mn);

5優勢:可適用於負邊權,可判負環(如果第n+1次仍存在鬆弛,則存在負環);

**什麼的......這個不重要(反正也幾乎不用),我們看優化版的spfa的吧

三、spfa演算法——bellman的優化

1核心思想:避免重複無效計算=>基於佇列的優化,能鬆弛的點才入隊。

2時間複雜度o(km)(ps:被卡時退化成o(nm));

3優勢:**較短,可判負環,可用於負邊權。

**如下:

void

spfa()//

存在負環

} }

}}

part2:多源最短路

四、floyd演算法

1核心思想:動規,f[i][j][k]=>  i->j只經過點1~k的min

2轉移方程:f[i][j]=min(f[i][j],f[i][k]+f[k][j])(第三維省略)

3時間複雜度o(n3)

核心**如下:(極簡)

for(int k=1;i<=n;k++)//

中轉站

for(int i=1;i<=n;i++)

for(int j=1;j<=n;j++)

f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

ps:k(中轉站)作為第三維一定是放在巢狀的最外層

ps:floyd在稠密圖中表現優秀,稀疏圖中可考慮n次dijkstra

part3:例題

eg1:奶牛的比賽

fj的n(1 <= n <= 100)頭奶牛們最近參加了場程式設計競賽:)。在賽場上,奶牛們按1..n依次編號。每頭奶牛的程式設計能力不盡相同,並且沒有哪兩頭奶牛的水平不相上下,也就是說,奶牛們的程式設計能力有明確的排名。 整個比賽被分成了若干輪,每一輪是兩頭指定編號的奶牛的對決。如果編號為a的奶牛的程式設計能力強於編號為b的奶牛(1 <= a <= n; 1 <= b <= n; a != b) ,那麼她們的對決中,編號為a的奶牛總是能勝出。 fj想知道奶牛們程式設計能力的具體排名,於是他找來了奶牛們所有 m(1 <= m <= 4,500)輪比賽的結果,希望你能根據這些資訊,推斷出盡可能多的奶牛的程式設計能力排名。比賽結果保證不會自相矛盾。

第1行: 2個用空格隔開的整數:n 和 m

第2..m+1行: 每行為2個用空格隔開的整數a、b,描述了參加某一輪比賽的奶 牛的編號,以及結果(編號為a,即為每行的第乙個數的奶牛為 勝者)

第1行: 輸出1個整數,表示排名可以確定的奶牛的數目

輸入 #    輸出 #

5 5      2

4 34 2

3 21 2

2 5

輸出說明:

編號為2的奶牛輸給了編號為1、3、4的奶牛,也就是說她的水平比這3頭奶牛都差。而編號為5的奶牛又輸在了她的手下,也就是說,她的水平比編號為5的

奶牛強一些。於是,編號為2的奶牛的排名必然為第4,編號為5的奶牛的水平必然最差。其他3頭奶牛的排名仍無法確定。(sourse:洛谷 p2419)

分析:這是一道floyd的變式,什麼時候能確定奶牛的具體排名呢?當且僅當其餘奶牛與它能比較時成立,因此,我們可以用

bool f[i][j] 處理關係(1表示i強於j),對輸入中任意一組關係a,b,f[a][b]=1,f[b][a]=0,用floyd的n次迴圈來處理,當f[i][k]=1&&f[k][j]==1時有f[i][j]=1

code:

1 #include 2

const

int n=101; 3

using

namespace

std;

4bool f[n][n];int n,m,ans=0;5

void judge(int

x)10

intmain()

17for(int k=1;k<=n;k++)

18for(int i=1;i<=n;i++)

19for(int j=1;j<=n;j++)

20 f[i][j]|=f[i][k]&f[k][j];//

精華,邏輯運算

21for(int i=1;i<=n;i++) judge(i);

22 cout<23return0;

24 }

eg3:奶牛接力(source:洛谷 

p2886)

fj 的n(2 <= n <= 1,000,000)頭奶牛選擇了接力跑作為她們的日常鍛鍊專案。至於進行接力跑的地點,自然是在牧場中現有的t(2 <= t <= 100)條跑道上。農場上的跑道有一些交匯點,每條跑道都鏈結了兩個不同的交匯點l1i和l2i(1 <=l1i <=1,000; 1 <= l2i <= 1,000)。每個交匯點都是至少兩條跑道的端點。奶牛們知道每條跑道的長度lengthi(1 <= l engthi <= 1,000),以及每條跑道鏈結的交匯點的編號。並且,沒有哪兩個交匯點由兩條不同的跑道直接相連。你可以認為這些交匯點和跑道構成了一張圖。為了完成一場接力 跑,所有n 頭奶牛在跑步開始之前都要站在某個交匯點上(有些交匯點上可能站著不只1頭奶牛)。當然,她們的站位要保證她們能夠將接力棒順次傳遞,並且最後持棒的奶牛要停 在預設的終點。你的任務是,寫乙個程式,計算在接力跑的起點(s)和終點(e)確定的情況下,奶牛們跑步路徑可能的最小總長度。顯然,這條路徑必須恰好經過n條跑道。

輸入 #1  輸出 #1

2 6 6 4 10

11 4 6

4 4 8

8 4 9

6 6 8

2 6 9

3 8 9

大意:給出一張無向連通圖,求s到e經過k條邊的最短路。

簡析:這道題又是floyd的變式(怎麼又是奶牛),我們可以用f[i][j][k](其中第三維可省略)來表示從i到j,經過k條邊的min

當k=0時只有f[i][i]=0;

當k=1時只有f[i][j]=way(i->j)更新

當k=2

#include using

namespace

std;

int n,t,s,e,top=0,re[1001

];struct

juzheng,ans,c;

//單開結構體,方便傳數

juzhen floyed(juzhen a,juzhen b)}}

returnc;}

void cheng(int n)

}int

main()

s=re[s],e=re[e];//

對映 memset(g.v ,0x3f,sizeof

(g.v));

memset(ans.v ,

0x3f,sizeof

(ans.v ));

for(int i=1;i<=top;i++) ans.v [i][i]=0;//

開始時(k=0)只有到自己的距離為零

cheng(n);

printf(

"%lld

",ans.v[s][e]);

return0;

}

to be continued...

最短路徑演算法 最短路

在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的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...