'一個著名的最貪心也最厲害的算法——Dijkstra算法'

算法 架構師公社 2019-08-18
"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法代碼實現:


"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法代碼實現:


一個著名的最貪心也最厲害的算法——Dijkstra算法


算法實例:

已經帶權有向圖G如下圖所示,現求節點2到節點3的最短路徑。這裡要求節點ID從0開始並且連續編號,且邊的權值大於0。後面的代碼實現也是要遵循這兩個前提條件的。

如果兩個節點見未直接相連,則節點間的距離設為無窮大,可用一個很大的數表示。

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法代碼實現:


一個著名的最貪心也最厲害的算法——Dijkstra算法


算法實例:

已經帶權有向圖G如下圖所示,現求節點2到節點3的最短路徑。這裡要求節點ID從0開始並且連續編號,且邊的權值大於0。後面的代碼實現也是要遵循這兩個前提條件的。

如果兩個節點見未直接相連,則節點間的距離設為無窮大,可用一個很大的數表示。

一個著名的最貪心也最厲害的算法——Dijkstra算法


圖中紅色數字表示邊的ID,圓圈中的數字為節點ID,邊旁邊的黑色數字表示節點間邊的權值。並且所有ID均不重複。

(1)初始時,標記起點2為已訪問的節點,並置於集合U中,此時集合U={2},集合Y={0,1,3}。

且初始化其它節點到起點2的距離distance[N]數組,N表示圖中節點數。distance[N]數組不僅需要保存其它節點到起點2的距離,也要保存起點2到達該節點的最短路徑的最後一箇中間節點,這裡稱為當前節點的前節點。如果沒有前一個節點則設為-1。

此時,distance[N]數組初始化為 {distance[0]={∞,-1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。標粗的表示該節點已經置於集合U中。

(2)在集合Y中找出距離起點2最短的節點,遍歷數組distance[N]得節點1距離起點2最近,並將其加入集合U中。此時集合U={2,1},集合Y={0,3}。

(3)以新加入集合U的節點1為中間節點,更新起點2到其它節點之間的最短距離。

對節點0,因為節點2到節點0的距離為無窮大∞,大於起點2通過節點1到節點0的距離2+3=5,並且節點0的前屈節點變為1,所以更新distance[0]={5,1};

對節點3,同理,因為節點2到節點3的距離為10,小於節點2通過節點1到節點3的距離1+∞=∞,所以無需更新。

所以,更新完之後的distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。

(4)重複步驟2,繼續在集合Y中尋找距離起點2最短的節點,並訪問它。遍歷數組distance[N]知道節點0到起點2的距離最短為5,其節點0加入集合U中。此時集合U={2,1,0},集合Y={3}。

(5)重複步驟3,以節點0為中間節點更新集合Y中節點到起點2的距離。因為distance[0].first+matrix[0][3]=5+4=9,小於distance[3].first=10,所以更新distance[3]={9,0}。

此時distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={9,0}}。

(6)重複步驟2,再集合Y中找出距離起點2最近的節點,遍歷distance[N]可知節點3距離最近,並將其納入集合U中。此時集合U={2,1,0,3},集合Y={}。

(7)重複步驟3,以節點3為中間節點更新集合Y中節點到起點2的距離,此時發現集合Y為空,過程結束。

最後我們獲得了加入集合U的所有節點,因為沒有節點都記錄了自己的前驅節點,所以可以獲得從起點到任意目的節點見的最短路徑。

實現代碼:

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法代碼實現:


一個著名的最貪心也最厲害的算法——Dijkstra算法


算法實例:

已經帶權有向圖G如下圖所示,現求節點2到節點3的最短路徑。這裡要求節點ID從0開始並且連續編號,且邊的權值大於0。後面的代碼實現也是要遵循這兩個前提條件的。

如果兩個節點見未直接相連,則節點間的距離設為無窮大,可用一個很大的數表示。

一個著名的最貪心也最厲害的算法——Dijkstra算法


圖中紅色數字表示邊的ID,圓圈中的數字為節點ID,邊旁邊的黑色數字表示節點間邊的權值。並且所有ID均不重複。

(1)初始時,標記起點2為已訪問的節點,並置於集合U中,此時集合U={2},集合Y={0,1,3}。

且初始化其它節點到起點2的距離distance[N]數組,N表示圖中節點數。distance[N]數組不僅需要保存其它節點到起點2的距離,也要保存起點2到達該節點的最短路徑的最後一箇中間節點,這裡稱為當前節點的前節點。如果沒有前一個節點則設為-1。

此時,distance[N]數組初始化為 {distance[0]={∞,-1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。標粗的表示該節點已經置於集合U中。

(2)在集合Y中找出距離起點2最短的節點,遍歷數組distance[N]得節點1距離起點2最近,並將其加入集合U中。此時集合U={2,1},集合Y={0,3}。

(3)以新加入集合U的節點1為中間節點,更新起點2到其它節點之間的最短距離。

對節點0,因為節點2到節點0的距離為無窮大∞,大於起點2通過節點1到節點0的距離2+3=5,並且節點0的前屈節點變為1,所以更新distance[0]={5,1};

對節點3,同理,因為節點2到節點3的距離為10,小於節點2通過節點1到節點3的距離1+∞=∞,所以無需更新。

所以,更新完之後的distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。

(4)重複步驟2,繼續在集合Y中尋找距離起點2最短的節點,並訪問它。遍歷數組distance[N]知道節點0到起點2的距離最短為5,其節點0加入集合U中。此時集合U={2,1,0},集合Y={3}。

(5)重複步驟3,以節點0為中間節點更新集合Y中節點到起點2的距離。因為distance[0].first+matrix[0][3]=5+4=9,小於distance[3].first=10,所以更新distance[3]={9,0}。

此時distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={9,0}}。

(6)重複步驟2,再集合Y中找出距離起點2最近的節點,遍歷distance[N]可知節點3距離最近,並將其納入集合U中。此時集合U={2,1,0,3},集合Y={}。

(7)重複步驟3,以節點3為中間節點更新集合Y中節點到起點2的距離,此時發現集合Y為空,過程結束。

最後我們獲得了加入集合U的所有節點,因為沒有節點都記錄了自己的前驅節點,所以可以獲得從起點到任意目的節點見的最短路徑。

實現代碼:

一個著名的最貪心也最厲害的算法——Dijkstra算法


求給定終點的最短路徑:

"

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。

一個著名的最貪心也最厲害的算法——Dijkstra算法


談到最短路,對於我來講最喜歡的算法不過floyd,無腦,簡單,好理解。但是面向oj上邊解題的方式來講,floyd的複雜度常常面對超時的可能,這也使得同樣好理解的dijkstra算法更受到青睞。今天咱們就來說說是典型最短路算法——Dijkstra算法

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法具體步驟為:

(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

一個著名的最貪心也最厲害的算法——Dijkstra算法


Dijkstra算法代碼實現:


一個著名的最貪心也最厲害的算法——Dijkstra算法


算法實例:

已經帶權有向圖G如下圖所示,現求節點2到節點3的最短路徑。這裡要求節點ID從0開始並且連續編號,且邊的權值大於0。後面的代碼實現也是要遵循這兩個前提條件的。

如果兩個節點見未直接相連,則節點間的距離設為無窮大,可用一個很大的數表示。

一個著名的最貪心也最厲害的算法——Dijkstra算法


圖中紅色數字表示邊的ID,圓圈中的數字為節點ID,邊旁邊的黑色數字表示節點間邊的權值。並且所有ID均不重複。

(1)初始時,標記起點2為已訪問的節點,並置於集合U中,此時集合U={2},集合Y={0,1,3}。

且初始化其它節點到起點2的距離distance[N]數組,N表示圖中節點數。distance[N]數組不僅需要保存其它節點到起點2的距離,也要保存起點2到達該節點的最短路徑的最後一箇中間節點,這裡稱為當前節點的前節點。如果沒有前一個節點則設為-1。

此時,distance[N]數組初始化為 {distance[0]={∞,-1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。標粗的表示該節點已經置於集合U中。

(2)在集合Y中找出距離起點2最短的節點,遍歷數組distance[N]得節點1距離起點2最近,並將其加入集合U中。此時集合U={2,1},集合Y={0,3}。

(3)以新加入集合U的節點1為中間節點,更新起點2到其它節點之間的最短距離。

對節點0,因為節點2到節點0的距離為無窮大∞,大於起點2通過節點1到節點0的距離2+3=5,並且節點0的前屈節點變為1,所以更新distance[0]={5,1};

對節點3,同理,因為節點2到節點3的距離為10,小於節點2通過節點1到節點3的距離1+∞=∞,所以無需更新。

所以,更新完之後的distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={10,2}}。

(4)重複步驟2,繼續在集合Y中尋找距離起點2最短的節點,並訪問它。遍歷數組distance[N]知道節點0到起點2的距離最短為5,其節點0加入集合U中。此時集合U={2,1,0},集合Y={3}。

(5)重複步驟3,以節點0為中間節點更新集合Y中節點到起點2的距離。因為distance[0].first+matrix[0][3]=5+4=9,小於distance[3].first=10,所以更新distance[3]={9,0}。

此時distance[N]取值情況為:{distance[0]={5,1}, distance[1]={2,2}, distance[2]={0,-1}, distance[3]={9,0}}。

(6)重複步驟2,再集合Y中找出距離起點2最近的節點,遍歷distance[N]可知節點3距離最近,並將其納入集合U中。此時集合U={2,1,0,3},集合Y={}。

(7)重複步驟3,以節點3為中間節點更新集合Y中節點到起點2的距離,此時發現集合Y為空,過程結束。

最後我們獲得了加入集合U的所有節點,因為沒有節點都記錄了自己的前驅節點,所以可以獲得從起點到任意目的節點見的最短路徑。

實現代碼:

一個著名的最貪心也最厲害的算法——Dijkstra算法


求給定終點的最短路徑:

一個著名的最貪心也最厲害的算法——Dijkstra算法


"