1. 程式人生 > 實用技巧 >6.4.2最短路徑

6.4.2最短路徑

加質Q(`⌒´Q)⊂(˃̶͈̀ε ˂̶͈́ ⊂ )mua

各位同學大家好,本節課我們來學習圖的第2個應用最短路徑問題,什麼是最短路徑問題呢?我們先來看一個生活中的例子,那麼在生活中現在有一個小鎮,小鎮上有若干個房子,我們每個房子之間可能會有這樣一條路把它們聯絡到一起,這就是彼此可以相互達到,那麼現在我們願意一個房子為起點,另一個房子為終點,想修算一下,從起點到終點最短的那條路徑是什麼?那麼根據我們之前學習過的廣度優先搜尋解決無全圖的單元最短路徑問題,我們可以去算這樣一條最短路徑,他是經歷了一個房子,那麼此時如果我們考慮路的長度,也就是每一條路每一條邊增加了一個權重,此時如何計算最短路徑呢?最短路徑也就是邊數最少的那條路徑嗎?答案是不是的,我們發現它的最短路徑是不是這一條啊?呃,權重此時如何計算最短路徑呢?自然路徑就是邊數最少的那條路徑嗎?答案是不是的,我們發現它的作用路徑是不是隻有一條啊,它今天的長度為期是最短的這樣一條,我們發現它是不是經歷了三條邊,所以說加上權重之後,我們就無法通過廣度優先搜尋來解決單元最短路徑問題了,那麼在這樣債權的圖當中,我們是如何定義最短路徑呢?權重之後我們就無法通過廣度優先搜尋來解決單元最短路徑問題了,那麼在這樣債權的圖當中,我們是如何定義最短路徑的呢?也就是兩個頂點之間帶全路徑長度最短的路徑為最短路徑,其中在全路徑長度表示為在帶全圖當中,把從一個頂點為等邊一個頂點u所經歷邊的全是之和稱為路徑的帶全路徑,長度與我們剛剛描述的是一致的,那麼知道什麼是最短路徑好,那我們本節課我們就來學習一下,如何在帶全圖當中計算最短路徑,那麼第1種方法則是理解斯特拉方法,第2種方法是弗洛伊德方法,我們首先來學習理解斯塔拉方法好,接下來我們再學習一下,理解斯塔拉演算法,它是計算債權主單元最短路徑演算法,這裡是從一個頂點為原點到其他各個頂點的這個樓叫三。它是計算帶全圖單元最短的演算法,這裡是從一個頂點為原點到其他各個頂點的這個樓叫好,我們來看怎樣實現一些司法,然後我們給用了三個陣列,我們先來看一下這三個輔助陣列都是代表什麼樣的含義烏,首先第1個輔助陣列是較為s的這個陣列,它表示的是我們已經計算完成的頂點的頂點集,也就是我們標記了已經計算完成矩陣模型的哪些景點,因為我們在實現這些SARS演算法的時候,每一個定點的作用就是我們是逐步計算完成的,所以我們要把這些應用計算完成的標記一下,那麼這樣一個速度怎樣,初始數字怎樣初始化呢?來看一下初始化時是吧?各個頂點對應下它的值都初始化為0唯一也就是老。1也就是我們把圓點加入到已經計算完成零點的這個集合當中,那麼這裡我們用0表示了,他為計算完成而用一表示讓他已經算完成好,這就是第1個輔陣列s了,第2個輔助陣列是distance的縮寫,dst它表示的就是最短路徑的長度什麼樣最短路徑的長度呢?是記錄從原點為圓弧到其他各個頂點當前的最短路徑長度,那麼我們用數字下標表示另一個端點的小的編號,而大家要注意點是這也是當前的最大長度,也就是說這樣一個數組是不斷更新的,我們在訓練的過程當中是不斷更新這樣一個數組的,那麼它是如何初始化的呢?陣列中的值初始化為原點到各個頂點邊的全值,也就是說第4套陣列它a下標的值,我們把它複製為數字。中的值初始化為原點到各個頂點邊的全值,也就是說disc陣列它a下面的值,我們把它複製為邊的那一個二位陣列0a下面下的是那麼這裡,因為我們的原點是v,零它的下標是0,所以我們賦指的是銀行的值,那麼根據我們原點的改變,那麼對應的航標也可能會發生改變,大家要在實際的使用當中注意一下這個問題,好這就是第2個數數,所以我們來看第3個數數字和pass,它是計算了什麼呢?它是儲存了我們這一條最短路徑經歷的頂點序變,那麼怎樣用這樣一個一位陣列儲存原點到剩下的所有頂點經歷的最短路徑的頂點序列呢?我們來看一下它是如何實現的進入從最短路徑中頂點的前學節點每一個我們是。頂點的前驅節點也就是每一個開始陣列下標時計算的是該頂點的前需頂點,我們是從哪一個頂點到達該頂點到 GPSI儲存的是為a到vI最短路徑上vI的前驅節點,那麼最後我們利用不斷的求前序節點,就可以計算v到vI的這一條就能靜了,那麼接下來我們就來看它的初始化,這樣一個數組初始化時,我們要若圓點v0到該頂點vI有一條有相邊或者是五相邊則願派3為0,否則用派3為負1,因為我們在初始時,是不是把這次的陣列中每一個對應下的20都計算為原點到對應相鄰節點,它這樣一條與上面的長度啊其實我們最開始時相應的這個零件就是你就試著用吧不知為對應。上一節點她這樣一條有下面的長度啊,所以其實我們最開始時與原點相應的這個零點他的錢去景點就是我們的原點,也就是這裡的v0,所以我們把它複製為對應v0的資料下標好,這就是fa的初始化好,這就是三個輔助陣列以及他們的初始化好,接下來我們要學習哪些四大演算法的具體演算法執行的過程,從這樣一個演算法的實現,其實與我們之前提到過的演算法非常的相似,但新法的策略,首先你就是啊初始化陣列,按照我們之前提到過的初始化方法,說實話三個輔助陣列,那麼這裡為了後續的說明方便,我們引用了一個幾個s,其實這個幾個s的意思用我們s的那個輔助數字是相同的,它儲存了所有我們已經求得的已經計算完成的哪些頂點加入。到已經計算完成的那些頂點,那麼首先我們所有將原點加入到代幾個當中,我們利用原點為v0,所以我們要將0加入到s結合當中好,這就是第1步初始化,接著第2步就是計算的過程,計算從頂點集合v減s中選出一個頂點為j,什麼意思呢?也就是從所有還沒有計算完成最短路徑的那些零點當中選出一個頂點vg,這樣一個頂點還需要滿足條件滿足什麼條件呢?就是後面所敘述的,它要滿足它是原點,到剩下的這些零點當中路徑長度最短的那一個頂點,也就是我們之後表示式所表達的意思,那麼找出這樣一個滿足該條件的頂點,然後將該點點的下標加入到我們的集合s當中,其實也就是將輔助下標s下的值賦值為一表示第三部第三。先要計算它了好,這就是第2步,其實我們來看第3步,第3步就是我們加入了這個頂點之後,是不是要對這次的陣列進行修改了,所以我們要修改此時從v0出發到集合未見s上任意頂點為k的最短路徑長度,因為我們引入了一個新的頂點為j,那麼因為vj到我們剩下的各個頂點上會存在邊這個因為存在著這些邊,所以它可能最大的問題差不多會發生改變,它可能會更小,那麼也就是若到vj這樣一個頂點的最短路徑,長度加上垂直到另一個頂點,vk的這樣一條邊,要小於原先我們儲存到z次數當中的長度時,我們則要對它進行修改,當更小的複製給sk,然後同樣我們要修改對應儲存路徑的這個輔助變數,輔助陣列態色魔,此時頂點vk是不是通過vc到vk這樣一條有線邊打到的呀是要交。對應我們儲存路徑的這一個輔助變數,輔助陣列派此此時頂點維k,是不是通過維j到維k這樣一條兩相邊達到的呀?所以要將數字下標為k的這樣一個值負值為g表示。路徑的這一個輔助變數輔助數總pass此時頂點為k,是不是通過vj到vk這樣一條有線邊打造的呀?所以要將數字下標為k的,這樣一個值負值為g表示從 v之一到達的vk好,這就是第3步,我們來看看小例子來理解一下這樣的第3步,那麼首先我們有一個v0,一個起始點起始景點,起始景點經歷了若干經典到達了我們的vk,這樣一個零點,我這個用虛線表示,那麼則表示這不是一條邊,這是一個路徑,那麼在其中經歷了若干個頂點,那麼它的長度是不是就是我們現在儲存的這個boss的培養,然後我們將vj又加入到了我們已經計算完成的這個頂點集當中,s當中此時我們又有了到vc的這樣一個這個路徑,它是ac的j從未。想變,那麼它的長度是什麼呢?它的長度則是對腰我們儲存在零件矩陣當中的量,也就是啊x啊,gk下表下大值,那麼我們在第3步所做出的判斷,是不是就是判斷d4k這樣一條路徑和d4j1加上r4j1,這樣一條路徑哪一個長度更短啊?我們要向d4k更新為更短的那一個值,這就是第3步的作用,那麼接下來我們只要重複二三步操作能減一次,為什麼有能減一次啊?因為除了原點是不是還剩n減1和頂點啊?直到x軸不好,全部頂點我們計算完成了原點到所有剩下的頂點的最短路徑長度,然後這就是解決斯特拉的演算法描述,可能光描述而演算法大家還是不太理解,有些細節不太清楚,接下來我們就來舉個例子,這是一個。實現怎樣實現該程式碼,其實實現方法用之前描述的演算法過程是一致的,首先它的名字叫吉傑斯特拉,承諾引數有兩個,第1個是這一個搜尋的圖片,第2個是我們的原點的編號,v首先第1步是不是還是初始化呀?這個程式碼就是初始化程式碼,那麼我們首先初始化了三個輔助的陣列,ss和disc,那麼它的速度大小為頂點的節點數量,然後我們實行了一個放迴圈,它則是對這三個輔助速度進行初始化的步驟,怎樣初始化呢?依舊是按照我們之前所敘述的初始化過程,我們將disc複製為對應好的所有的邊,也就是對應所有邊大的全值,然後sa我們要把它都複製為0,也就是s的這個輔助所都全賦值為0小云。代表的是無窮大,我們在語言編寫當中可以先用麥克斯生命為它是一個非常大的整數,因為這個整數表示無窮大,那麼如果它小於無窮大時則代表它存在這樣一條有相變墨,所以就把它路徑的前驅節點負責我們的這個起始端點v,然後如果它是無窮大的話,則說明從原點到這樣一個頂點是沒有有向邊的,所以把它初始化為負1,它沒有任何大的前去節點,接下來的兩個語句,sv賦值為e所代表的是我們初始化了這個原點,將原點的下標賦值為e,並把pass下標下的值賦值為-1,為什麼把原點判斷下,標下的值要單獨計算為-1呢?因為我們知道在連線矩陣當中,行標和列標相同的這個位置的值,我們要存放為0特殊的三四三。粗放為-1,接下來我們剩下的是不是隻有2343個步驟了,那麼第1個負迴圈實現的則是第4個步驟,也就是我們重複計算23的這個過程,首先這一部分是第2個步驟,第2個步驟大家還記得是什麼嗎?是挑選符合條件的第1次陣列下標下最小的那個值,我們首先初始化了兩個變數,兩個輔助變數,第1個未變數,我們把它初始化為最大值,這個最大值是我們體現生命好的是當前整形變數,我們看到最大的那個數,它的作用就是幫助我們來挑選最小的那一個值,還有第2個屬於變數u,那麼接下來就是一個迴圈語句,我們就是電力這個陣列變電機的陣列,找到那個最小的值,他的條件是什麼呢?判斷條件要滿足兩個滿足哪兩個呢?第1個則是該頂點已經是在剩下的頂點期當中,也就是在那些沒有計算完。一定是在剩下的零點幾當中,也就是在那些沒有計算完最短路徑的面積當中,那麼我們判斷方法則是sj是否等於00表示為它沒被選入,然後還要滿足一個條件,就是它要比我們當前的這個面儲存所有,只要小不斷的修改,我們更小的這個值,那麼這個我們就是找尋數字當中最小值的方法,然後如果。被選入然後還要滿足一個條件,就是它要比我們當前的這個面儲存縮小值,要小不斷的修改,我們更小的這個值,那麼這個我們就是找尋數字當中最小值的方法,然後如果它更小的話,則要修改兩個變數,也就是我們剛剛提到過的那兩個輔助變數面要向它修改為新的這個最小的值,u要向它儲存為最小值的這個頂點的下標,然後這就是一個for迴圈語句找尋符合條件的最小值,然後我們要把對應u也就是對應我們剛剛找過的那個最小值的數字下標,將它加入到已經完成的集合當中,這就是52條的程式碼實現,接下來就是步驟,3不是3是什麼呢?或者3是我們要修改對應的輔助陣列,因為我們新加入了一個頂點,那麼新加入的頂點會帶來很多邊帶來很多變的同時就會營銷。第1次陣列最小值陣列產生影響,那麼我們想要對它們進行修改,首先我們還是放迴圈語句迴圈的,對於數字當中每一個頂點進行判斷,那麼判斷條件你就有兩個依舊還要滿足它是未被標記的,然後滿足的則是我們之前提到過的那一個判斷表示式,那麼如果它要小的話,則把陣列當中的值進行更新,更新回來最小的那一個,那麼對應pass陣列下的指令需要更新,因為我們通過了一個新的頂點,到達了我們對應的這個頂點,那麼新的頂點的陣列下標,就是我們之前加入的那一個頂點的編號,也就是我們儲存的這個u好,這就是第3個步驟,接下來我們只要迴圈23這個步驟,就可以實現我們的第1次納拉演算法是多少呢我們在這裡看到了一個幾點數量極大所以他,那麼接近斯卡拉,它的演算法時間複雜度是多少呢?我們在這裡看到了一個二重迴圈,迴圈次數都是幾點,數量的數量極大,所以它的時間複雜度為大,o為方。斯特拉它的演算法時間複雜度是多少呢?我們在這裡看到了一個二重迴圈,迴圈次數都是幾點,數量的數量極大,所以它的時間複雜度為大,o為方是就是李傑斯,他演算法的時間複雜度好,那麼接下來我們來看一下這些四大演算法它適用於所有的有相同嗎?我們來看這樣一個例子,我對該圖做一個小的修改,把從1~2這條小牆邊從一個正值修改為了一個負值,也就是說在該圖當中存在帶有負全值的變,那麼我們來看一下這樣的偶像圖是否可以運用以及斯特拉演算法來計算單元最短的叫,首先還是執行這些4套演算法的這個過程,輔助陣列以及初始化依舊從0.0作為原點進行實現之前提到的都是一樣的也沒有作出修改然後直行到第二輪時我們發現我們選了。然後執行到第2輪時,我們發現我們是不是挑選了頂點一樣,因為頂點一對應它的路徑差不多最短,切它也沒有被標記,然後挑選0.1之後,你就要把它加入到標記的這個集合當中,然後要修改disc大數下面下的值,我們加入了0.1之後是不是引入了從1~2和從1~3這兩條就相變了,那麼我們來看到達頂點2的整個意思,我們以前儲存的這個紙是3,它是從0~2這樣一條有向邊,這樣一條有效的路徑它的權重為3,然後我們因為加入了0.1,是不是還存在另外一條路徑可以到達天天2啊,也就是從0~1再到2,這樣一條有效的路徑直我們來看,如果按照我們之前的演算法描述過程,我們在判斷時一定判斷的這些頂點都是從危險s也就是剩下的零點當中挑選頂點卻比較的。一定看到的這些頂點都是從v減s,也就是剩下的零點當中挑選,零點去比較的,也就是對腰輔助數字s,那麼我們發現是不是2向下的值為1啊,所以此時更新過後到達頂點2的作用路徑依舊是3,但是我們發現加入1~2這樣一條負全值偶像變時,從0~1再到2,它的全值大小是不是為2啊?他要比三更小,但是底下4323法並沒有把它更新為2,所以我們要記住,底下四大演算法並不適用於含有負全面的圖,這就是底下斯特拉三法的一個曲線性,那麼有沒有什麼樣的演算法可以以集結423法它的適用性更廣呢?啊,這個弗洛伊德演算法它是什麼呢?它是計算各頂點之間的計算中心,也就是說弗洛伊德演算法計算完成之後,我們可以將頂點之間的所有的算入叫都可以表示出來,那麼我們來看一下它是如何實現的,它的演算法思想是必推的產生一個ng的發生序列,那麼這樣的發生序列則儲存了對應從某一個定點到達,另一個定點導致的叫那麼行號,也就表示的是起始頂點列號表示的字是終止頂點,為什麼是這樣一個序列呢?這樣一個結果矩陣,其實它與我們對應幾個4313法是一樣的,也是逐步上升的過程,從大f1>0一直到大an-1,那麼這裡大於負1代表的是我們初始化的這一個矩陣,因為因為我們有n個頂點,所以我們要逐步生成n個矩陣,那麼這樣一個矩陣表示的是什麼含義呢?那上面這個小標又是什麼樣的含義呢?我們來看它的含義。因為因為我們有n個零點,所以我們要逐步生成n個矩陣,那麼這樣一個矩陣表示的是什麼含義呢?它上面這個小標又是什麼樣的含義呢?我們來看它的含義。A象標是kag下標下的值代表是頂點為a到頂點為j的最短路徑的長度,也就是起始端點為vI中式端點為為之打上一條有效路徑直且該路徑經過的頂點,編號大於k,也就是說如果上標是k的話,則為abc經歷的這樣一條路徑,它經歷頂點編號不會大於k,也就是從0~k-1,怎樣從k減1這樣一個矩陣到達ak這樣一個矩陣呢?我們來看一下初始化時,我們將a這個上標為-1的矩陣初始化為我們圖的這個臨界矩陣,那麼初始化之後,我們就開始地推我們來看我們是如何從k減1到達k的。那麼初始化之後我們就開始底推,我們來看我們是如何從k減1到達k的,我們是這樣來計算的,它下週下的每一個值進行這樣一次修改,也就是計算一個最小值的過程,比如說我們來看aj下表下的值怎樣修改呢,我們計算兩個值的最小值,把最小的那一個複製為ak,第1個值是ak-1這個矩陣ag下面下的值,第2個我們所要比較的值是ak-1ak加上ak-1kj判斷這樣一個和和ac-1aj哪一個更小?把更小的複製為我們新生成矩陣對應下標ac下的值,就是說我們沒有加入k零點來看一下它的作用容器和加入了k零點來看一下它的最小的像哪一個更小沒有加入。這樣的長度從a到g,第2個則是計算了加入了k零點之後,從a到j到最小路徑的長度,我們來看一下我們是怎樣計算加入k零點之後的這樣一個最短路徑的,那麼第1個值是不是就是從其實零點到頂點k這樣一條最短路徑,然後加上呢,是從k頂點c到終日頂點c的這樣一條最大值降,那麼其實頂點到達k零點,k零點,再從k零點c從k零點到達終止,零點加起來,是不是就是從歧視零點到達終止頂點的這樣一條最大的價值,但是我們是不是途徑老kr,所以說我們就把k零點加入了進來,那麼這樣說依舊有點衝向我們來看這樣一個例子,現在我們有一個起始0點vI,那麼它可以通過一個路徑到達vj,它是最短的假設,我們計算到了ak減1這個矩陣。到了這個ak頂點之後,是不是從vI到vk有一條路徑,那麼它的自然路徑也就是ak-1ak,這樣下標下的值接著上,我們又從vk到達vj,有這樣一條最短路徑,它的大小是不是就是ak減1kj這樣下標下的值啊?這樣我們就有兩種方法到達了vj這個頂點,那麼我們就要判斷則是上述這個公式判斷哪一個路徑更小剛剛小的賦值給ak下標下的這個值,也就是我們加入k之後更新的這個矩陣,好,這就是我們地推的方法,其實這樣一個演算法,我們利用了演算法分析課程當中的另一種方法,就是動態規劃的方法,有興趣的同學可以去了解一下考察首先是。就是把對應到我們存放身邊的這個以及矩陣複製給我們這個新生成的變數,a這個變數矩陣,首先這個矩陣其實是沒有圖形任何頂點的,接下來的第1步,我們想要加入頂這個頂點,生成a頂那個矩陣,怎麼樣加入領車停電呢?是不是要對軍人當中的每一個指標判斷進行修改啊,那麼我們就來判斷一個嘗試一下,看看它是如何進行判斷的。其實判斷過程就是我們剛剛描述的那個過程,我們來找一個母角,這條路徑是不是表示的是從頂點2~達0.1的這樣一條有效的路徑,大家注意,這不是邊,這是有效的路徑,那麼這裡有一個相互作用表示正無窮所代表沒有這樣一條路徑,然後怎樣進行修改呢?首先我們是不是要把0.0加入進來啊?加入的方法是不是就是之前所敘述的那一個方法其實零點七十二點到底。它的程式碼實現非常簡單,我們通過了一個三重迴圈,這就是它主要的實驗程式碼,我們來看一下它的函式函式,首先我們聲明瞭一個輔助一個結果的那個矩陣a,那麼它的大小為乘n的就是節點數量的平方,然後我們通過了一個二重迴圈來初始化了這個a矩陣,也是將對應的連線矩陣的值複製給了這個矩陣,我們需要一個二重迴圈,然後接下來這個三重迴圈則是我們主要的演算法實現的過程,那麼第1種迴圈是不是迴圈測試,我們要把每個頂點第1次的加入進來了,那麼加入進來之後,那麼加入一個頂點之後,我們只要對訓練當中每一個值進行修改,所以在第1個迴圈下面裡邊是不是一個二重迴圈啊這是每一個超這就是為什麼需要三個條件就是我們。則是對劇本當中每一個只要進行修改的過程,這就是為什麼我們需要三個迴圈,最終的這個判斷條件判斷的就是我們之前提到過的那個遞推關係式,也就是判斷我們新生成的這一條有效路徑直,會不會比我們之前存放的從a到j的這一條的強度性更短,如果根本的話我們是要更新ac好,這就是判斷條件以及執行過程,我們通過這樣一個三重迴圈實現了弗洛伊德演算法,那麼其實在很多比試當中,大家更喜歡使用這樣一個演算法,為什麼呢?因為我們發現他是不是非常好記呀,DJ斯特拉斯奧雖然它有針對性,但是它其實不太好記,那麼複述一個演算法,我們則需要一個三方迴圈就可以實現了,它的時間可能度自然而然是幾點數量級的地方,因為我們有這樣一個三床的迴圈,所以同學們可能會有結論,除了一個演算法,一定要比迪斯科拉演算法要更慢,它的效率要更低結果是不是。這樣一個三中的演算法,所以同學們可能會有結論,除了一個演算法,一定要比第422演算法要更慢,它的效率要更低,當然是不是的,我們發現它涉及到的結果是不是每一對頂點之間存在的最大估計啊,而這些2/4的演算法只計算了一個頂點到剩下的所有頂點的最大值,如果在這些3l演算法當中,我們想計算所有頂點時間的,雖然不行的話,我們也要加上一個迴圈迴圈,對每一個頂點計算到剩餘頂點的算,我們就這樣的話是不是一個演算法和服了一個演算法,它的時間複雜度其實是不是相似的好,這就是服了一個演算法,那麼在課程當中,其實我們對這兩種演算法它實現的步驟,也就是說我們給你一個有向圖,給你一個五香圖,讓你根據不同的演算法來寫出它的生成步驟,而對程式碼的編寫要求其實是非常小的,大家也可以酌情的去學習,酌情的去記憶。