最短路演算法
今天,我們來總結圖的最短路演算法,它的基礎演算法如下:
part1:單源最短路
一、dijkstra演算法。
1核心思想:貪心演算法=>每次找最短的邊,標記該點並對其餘未標記點鬆弛。
2模板:
voiddijkstra()
//ans為dis[k]
}
時間複雜度:o(n2)
3優化:找最短邊的時候可採用大根堆(優先佇列實現) 時間複雜度o(m+nlogn),**如下:
intn,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優勢:**較短,可判負環,可用於負邊權。
**如下:
voidspfa()//
存在負環
} }
}}
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 24 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 2const
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 1011 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 usingnamespace
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...