最短路優(yōu)化

最短路優(yōu)化

寫在前面

上次講了最短路的基礎(chǔ)弦追,但是像最短路這種博大精深(坑特別深)的算法。花竞。劲件。是肯定有優(yōu)化的啦。這一篇是給有最短路基礎(chǔ)的人看的约急,假如沒有嘛零远。⊙岜危可以看看我以前寫的最短路基礎(chǔ)

SPFA

我把這個算法挪到這邊來寫了牵辣,原因有兩個:第一個是我上次懶得寫了。奴饮。
第二個是這個算法比較難纬向,所以放在了優(yōu)化這邊一起寫,而且它本身就是對貝爾曼福德的優(yōu)化戴卜。
不說廢話了罢猪,let's begin
spfa 算法可以適用于負邊權(quán)的情況,是 bellman-ford 的隊列優(yōu)化叉瘩。
假設(shè)存在 G=<V,E>膳帕,dis[i]記錄 V0 到 i 的最短距離,pre[i]記錄從 V0 到 i 路徑 上 i 的前面的一個頂點;
step1.將所有頂點對之間距離初始化為無窮大(dis[i][j]=無窮大),pre[i]=i危彩, vis[i]=0攒磨,將源點入隊;
step2.讀取隊頭頂點 now,并將隊頭頂點 now 出隊(記得消除標記)汤徽,將與點 now 相連的所有點 next 進行松弛操作(還記得嗎娩缰,上一篇講過),更新 dis[next]谒府,另外拼坎,如果點 next 沒有 在隊列中,那么要將點 next 入隊(記得標記)完疫,如果已經(jīng)在隊列中了泰鸡,那么就不 用入隊(如果某個頂點入隊超過 V 次,則說明圖中有負環(huán)壳鹤,直接跳出);
step3.重復(fù) step2盛龄,直到隊空為止就完成了單源最短路的求解。
這是主要思路芳誓。
下面有個圖解(無恥的轉(zhuǎn)自某博客)??

spfa_1.jpg
spfa_2.jpg

其實它和bfs非常類似(bfs在我創(chuàng)建的專題里有人講過)余舶。只是bfs中的一個點出了隊列就不會再回來了,而最段路中由于有環(huán)的存在锹淌,導(dǎo)致了一個點可能進入隊列多次匿值。
spfa函數(shù)附上


spfa函數(shù).png

下面是洛谷題解的一個,感覺注釋寫的挺詳細赂摆,也附上挟憔。

void spfa()
{
  queue<int> q; //spfa用隊列,這里用了STL的標準隊列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //帶權(quán)圖初始化
    vis[i]=0; //記錄點i是否在隊列中库正,同dijkstra算法中的visited數(shù)組
  }
  q.push(s); dis[s]=0; vis[s]=1; //第一個頂點入隊曲楚,進行標記
  while(!q.empty())
  {
    int u=q.front(); //取出隊首
    q.pop(); vis[u]=0; //出隊標記
    for(int i=head[u]; i; i=edge[i].next) //鄰接表遍歷厘唾,不多解釋了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入隊則入隊
        {
          vis[v]=1; //標記入隊
          q.push(v);
        }
      }
    }
  }
}

spfa這個算法非常好用(功能強大褥符,效率高??)
基本上單源最短路的題都可以用spfa,墻裂推薦

狄杰斯特拉(堆優(yōu)化)

真不知道為什么會有人把它念成迪克特斯拉??
(需要有堆的基礎(chǔ))
思路:在尋找周圍最小點的時候抚垃,用最小堆喷楣,可以用 O(log n)的時間找出最小的可到達點。
是不是感覺很蛋疼鹤树。铣焊。但是很秀??
最小堆:最小堆,是一種經(jīng)過排序的完全二叉樹罕伯,其中任一非終端節(jié)點的數(shù)據(jù)值均不大于其左子節(jié)點和右子節(jié)點的值曲伊。
最小堆后面可能會說,但是這里嘛。坟募。就很不負責任的推薦一個別人的博客:別人家的最小堆
別嫌棄呀岛蚤。。
堆優(yōu)化的主要思想就是使用一個優(yōu)先隊列(就是每次彈出的元素一定是整個隊列中最小的元素)來代替最近距離的查找懈糯,用鄰接表代替鄰接矩陣涤妒,這樣可以大幅度節(jié)約時間。
在這里有幾個坑要先填一下:
首先來講赚哗,優(yōu)先隊列的數(shù)據(jù)類型應(yīng)該是怎樣的呢她紫?
我們知道優(yōu)先隊列應(yīng)該用于快速尋找距離最近的點。由于優(yōu)先隊列只是將最小的那個元素排在前面屿储,因此我們應(yīng)該定義一種數(shù)據(jù)類型贿讹,使得它包含該節(jié)點的編號以及該節(jié)點當前與起點的距離。
辣么扩所。围详。我們應(yīng)該在什么時候?qū)﹃犃羞M行操作呢?
隊列操作的地方祖屏,首先就是搜索剛開始助赞,要為起點賦初始值,此時必須將起點加入優(yōu)先隊列中袁勺。該隊列元素的節(jié)點編號為起點的編號雹食,該節(jié)點當前與起點的距離為0。
那么如果一個節(jié)點到起點的最短距離通過其他的運算流程發(fā)生了變化期丰,那么如何處理隊列中的那個已經(jīng)存入的元素群叶?
事實上,你不需要理會隊列中的元素(暴力無視)钝荡,而是再存入一個就行了街立。因為如果要發(fā)生變化,只能將節(jié)點與起點之間的距離變得更小埠通,而優(yōu)先隊列恰好是先讓最小的那個彈出赎离。
因此,輪到某一個隊列元素彈出的時候端辱,如果有多個元素的節(jié)點編號相同梁剔,那么被彈出的一定是節(jié)點編號最小的一個。等到后面再遇到這個節(jié)點編號的時候舞蔽,我們只需要將它忽略掉就行了荣病。
是不是感覺hin棒???
最小堆優(yōu)化的迪杰有一個模版題:

例:網(wǎng)吧
【問題背景】
綿陽中學(xué)以人數(shù)眾多而聞名渗柿。三個年級共有 10000 多人个盆,學(xué)生多了附近的 網(wǎng)吧也多。Mzoiers 都熱衷于 Dota,可學(xué)校的機子配置相當差(評測服務(wù)器除外)颊亮, 根本不能玩 Dota鸡岗,那就只有去網(wǎng)吧。星期天到星期五都是晚上 10:20 才下晚自 習编兄,幾乎沒時間玩轩性。
然而星期六下午放假是絕好的時間,但是學(xué)校人多啊狠鸳,一放學(xué)去網(wǎng)吧的人就 開始狂奔揣苏,競爭之激烈,搶到機子的難度非常之大件舵。往往在我們到達網(wǎng)吧之前都 坐滿了卸察。
學(xué)校到網(wǎng)吧的路是錯綜復(fù)雜的,以致于到一個自己想去的網(wǎng)吧都有非常多的 路線可以選擇铅祸,而路線的長度又不相同坑质,這樣就決定了要花費的時間,因此想要 盡快到達临梗,選擇一條最佳的線路是很有必要的涡扼。
【問題描述】
為了簡化問題,我們把學(xué)校與周邊的網(wǎng)吧看做圖中的頂點盟庞,學(xué)校與網(wǎng)吧吃沪,網(wǎng) 吧與網(wǎng)吧之間的路線看做邊,每個邊都有一個權(quán)什猖,表示我們走完這條路的時間票彪, 由于放學(xué)人流量大,如果反向走會有危險不狮,因此這是一個有向圖降铸。
我的的學(xué)校在 S 點,想要去的網(wǎng)吧在 T 點摇零。你的任務(wù)就是選擇一條最佳路線推掸, 使得從學(xué)校到目的地網(wǎng)吧的時間最短,你只需要輸出最短到達時間即可遂黍。 【輸入文件】
netbar.in 中共有 M+2 行數(shù)據(jù)
第一行兩個整數(shù) N终佛,M,表示點數(shù)和邊數(shù)。
然后 M 行每行 3 個正整數(shù)(u站宗,v臼婆,t),表示有一條可由 u 到 v 耗時為 t 的邊通贞。 最后一行兩個正整數(shù) S寥闪、T材失。
【輸出文件】
netbar.out 中敬飒,只有一行邪铲,一個整數(shù)表示最短時間。如果 S无拗、T 之間不存在通 路則輸出“No Solution!”(雙引號不輸出带到,“!”為西文標點)。
【輸入樣例】
44 123 2 4 10 135 345 14
【輸出樣例】
10
【數(shù)據(jù)規(guī)挠⑷荆】
對于 30%的數(shù)據(jù)保證有 1<N<=1000揽惹,1<=M<=1000; 對于全部的數(shù)據(jù)保證有 1<N<=10000,1<=M<=100000四康。

注明:我不是綿中的(也不打算去)搪搏,我和綿中也沒有什么利益關(guān)系。題目不是我出的闪金,如果覺得它對綿中不懷好意疯溺。。哎垦。也別找我
下面附上標程:


迪杰1.jpg

迪杰2.jpg
迪杰3.png
迪杰 4.jpg

迪杰優(yōu)化一般情況下用的不是很多囱嫩,但是在某些特殊場合是可以用的。也看得出來優(yōu)化不是很復(fù)雜漏设,比較好理解挠说。對迪杰情有獨鐘的同學(xué)可以記一下。

ending

最短路這個博大精深的算法也算是圖論的核心愿题,所以损俭。。學(xué)好最短路很重要潘酗。
看在我這么用心的份上滋瓷一下唄杆兵。。
不要問我為什么這篇的程序都是圖片仔夺。琐脏。
其實。缸兔。介紹一個方法(也不知道算不算了)日裙。在遇到最段路的題的時候,windows系統(tǒng)的同學(xué)可以打開畫圖惰蜜,把樣例畫成一個圖昂拂,在推一遍,可以看得很直觀抛猖,免得對著幾個數(shù)字空想格侯,很抽象鼻听。
(老師附體)(苦口婆心)以上內(nèi)容可能有點難度,建議多看幾遍联四,多想幾下撑碴,最好能推一遍。朝墩。醉拓。
(在你嫌棄我之前跑掉)??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市收苏,隨后出現(xiàn)的幾起案子廉嚼,更是在濱河造成了極大的恐慌,老刑警劉巖倒戏,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怠噪,死亡現(xiàn)場離奇詭異,居然都是意外死亡杜跷,警方通過查閱死者的電腦和手機傍念,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葛闷,“玉大人憋槐,你說我怎么就攤上這事∈缰海” “怎么了阳仔?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扣泊。 經(jīng)常有香客問我近范,道長,這世上最難降的妖魔是什么延蟹? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任评矩,我火速辦了婚禮,結(jié)果婚禮上阱飘,老公的妹妹穿的比我還像新娘斥杜。我一直安慰自己,他們只是感情好沥匈,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布蔗喂。 她就那樣靜靜地躺著,像睡著了一般高帖。 火紅的嫁衣襯著肌膚如雪缰儿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天棋恼,我揣著相機與錄音返弹,去河邊找鬼。 笑死爪飘,一個胖子當著我的面吹牛义起,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播师崎,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼默终,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了犁罩?” 一聲冷哼從身側(cè)響起齐蔽,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎床估,沒想到半個月后含滴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡丐巫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年谈况,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片递胧。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碑韵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缎脾,到底是詐尸還是另有隱情祝闻,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布遗菠,位于F島的核電站联喘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辙纬。R本人自食惡果不足惜耸袜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牲平。 院中可真熱鬧堤框,春花似錦、人聲如沸纵柿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昂儒。三九已至沟使,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渊跋,已是汗流浹背腊嗡。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工着倾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人燕少。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓卡者,卻偏偏與公主長得像,于是被迫代替她去往敵國和親客们。 傳聞我的和親對象是個殘疾皇子崇决,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354