摘要:說明算法運行結束后,會得到從源節點到其它所有節點的最短路徑,同時得到每個節點的前驅節點,不能包含負權回路如圖但可以包含圖,這里所說的負權環路是指環路的權值總和為正或為負圖圖松弛操作概念松弛操作針對的操作對象是圖中的邊,對圖中任意一條邊,
1. 說明
Bellman-Ford算法運行結束后,會得到從源節點 s 到其它所有節點的最短路徑,同時得到每個節點的前驅節點,Bellman-Ford不能包含負權回路如圖 1.1 但可以包含圖 1.2,這里所說的負權環路是指環路的權值總和為正或為負
圖 1.1
圖 1.2
2. 松弛操作2.1. 概念
松弛操作針對的操作對象是圖中的邊,對圖中任意一條邊e=(u,v),假設在對e進行松弛之前,已經知道從源節點s到u的最短估計距離u.d,從源點到v的最短估距離v.d,同時邊e的權重為w,松弛操作就是更新節點v的最短估計距離v.d = min{v.d, u.d + w}, 由于初始狀態是,所有節點的最短估計路徑都設為 Infinity 即無窮大,所以在任意時刻,u.d和v.d都是存在的
2.2. 舉例
初始時,v1,v2,v3,v4四個節點的最短估計路徑都為 Infinity ,求解從v1節點到其它所有節點的最短路徑距離,所以將v1.d設置為0
圖 2.2
對邊(v1,v2)進行松弛 有 v1.d = 0,v2.d = Infinity,w(v1,v2) = 1; 所以v2.d被更新為 v2.d = v1.d + w(v1,v2) = 1;
對邊(v1,v3)進行松弛 有 v1.d = 0,v3.d = Infinity,w(v1,v3) = 3; 所以v3.d被更新為 v3.d = v1.d + w(v1,v3) = 3;
對邊(v2,v4)進行松弛 有 v2.d = 1,v4.d = Infinity,w(v2,v4) = 5; 所以v4.d被更新為 v4.d = v2.d + w(v2,v4) = 6;
對邊(v3,v4)進行松弛 有 v3.d = 3,v4.d = 6,w(v3,v4) = 1; 所以v4.d被更新為 v4.d = v3.d + w(v3,v4) = 4;
3. js中如何表示無窮大在全局使用 Infinity 來表示正無窮大,用 -Infinity 表示負無窮大,同時可以使用 Number.POSITIVE_INFINITY 表示正無窮,用Number.NEGATIVE_INFINITY 表示負無窮,這幾個常量都可以與其它類型的數字比較大小,在 Number中還有其它的常量,讀者可以在新版的瀏覽器控制臺 執行 console.dir(Number) 去查看
4. 相關數據結構及初始化算法的輸入數據//節點數據結構 function Vertex() { if (!(this instanceof Vertex)) return new Vertex(); this.id = null; //用來標識節點 this.data = null; //節點數據 } //邊數據結構 function Edge() { if (!(this instanceof Edge)) return new Edge(); this.u = null; //邊的起點節點 this.v = null; //邊的終點節點 this.w = null; //邊的權重 } //圖 function Graph() { if (!(this instanceof Graph)) return new Graph(); this.vertices = []; //圖的節點集 作為算法的輸入數據 this.edges = []; //圖的邊集 作為算法的輸入數據 this.refer = new Map(); //節點標識表 } Graph.prototype = { constructor: Graph, initVertices: function(vs) { for (let id of vs) { let v = Vertex(); v.id = id; this.refer.set(id, v); this.vertices.push(v); } }, initEdges: function(es) { for (let r of es) { let e = Edge(); e.u = this.refer.get(r.u); e.v = this.refer.get(r.v); e.w = r.w; this.edges.push(e); } } } var vertices = ["v1", "v2", "v3", "v4"]; var edges = [ {u:"v1", v:"v2", w:1}, {u:"v1", v:"v3", w:3}, {u:"v2", v:"v4", w:5}, {u:"v3", v:"v4", w:1}, {u:"v4", v:"v2", w:-3} ]; var g = Graph(); g.initVertices(vertices); g.initEdges(edges);5. Bellman-Ford算法
5.1. 算法介紹
BellmanFord算法的原理就是對輸入的所有邊都進行 |V| - 1次松弛操作,為什么是 |V| - 1次見 5.3.
5.2. 算法的js實現
function BellmanFord(vertices, edges, source) { let distance = new Map(); //用來記錄從原節點 source 到某個節點的最短路徑估計值 let predecessor = new Map(); //用來記錄某個節點的前驅節點 // 第一步: 初始化圖 for (let v of vertices) { distance.set(v, Infinity); // 初始化最短估計距離 默認無窮大 predecessor.set(v, null); // 初始化前驅節點 默認為空 } distance.set(source, 0); // 將源節點的最短路徑估計距離 初始化為0 // 第二步: 重復松弛邊 for (let i = 1, len = vertices.length - 1; i < len; i++) { for (let e of edges) { if (distance.get(e.u) + e.w < distance.get(e.v)) { distance.set(e.v, distance.get(e.u) + e.w); predecessor.set(e.v, e.u); } } } // 第三步: 檢查是否有負權回路 第三步必須在第二步后面 for (let e of edges) { if (distance.get(e.u) + e.w < distance.get(e.v)) return null; //返回null表示包涵負權回路 } return { distance: distance, predecessor: predecessor } }
5.3. 為什么第二步中的要加最外層循環,并且是 |V| - 1 次
最外層增加循環且次數為|V| - 1次,原因是對輸入的邊的順序是沒有限制的,在 2.2.節 中,我們用了四次松弛操作就找到了從節點v1到其它所有節點的最短路徑,是因為 2.2.節 中邊是按照一定的順序選取的,開始時選取的是與源節點直接相領的邊,接下來選取邊的起始節點是已經被松弛過的邊連接的終止節點,如果對邊的選取順序為 (v2,v4),(v3,v4),(v1,v2),(v1,v3) 這種情況就需要最外層的循環,并且需要兩次,考慮最壞的情況,如圖
圖 5.3
并且邊的選取順序為(v3,v4),(v2,v3),(v1,v2),這樣對于四個節點需要三次最外層的循環,即|V| - 1
在《算法導論》中,有這樣的描述:
當進行第 i 次循環時,一定包含邊 (v[i-1],v[i]), 這句話的意思時,如果存在從源節點s到v的最短路徑,那么在第i次循環結束后,節點 v[i-1].d和節點v[i].d一定不為 Infinity ,為一個具體的值
輸入圖為 圖 1.2 從 節點v1到其它所有節點的最短路徑
//節點數據結構 function Vertex() { if (!(this instanceof Vertex)) return new Vertex(); this.id = null; //用來標識節點 this.data = null; //節點數據 } //邊數據結構 function Edge() { if (!(this instanceof Edge)) return new Edge(); this.u = null; //邊的起點節點 this.v = null; //邊的終點節點 this.w = null; //邊的權重 } //圖 function Graph() { if (!(this instanceof Graph)) return new Graph(); this.vertices = []; //圖的節點集 this.edges = []; //圖的邊集 this.refer = new Map(); //節點標識表 } Graph.prototype = { constructor: Graph, initVertices: function(vs) { for (let id of vs) { let v = Vertex(); v.id = id; this.refer.set(id, v); this.vertices.push(v); } }, initEdges: function(es) { for (let r of es) { let e = Edge(); e.u = this.refer.get(r.u); e.v = this.refer.get(r.v); e.w = r.w; this.edges.push(e); } } } function BellmanFord(vertices, edges, source) { let distance = new Map(); //用來記錄從原節點 source 到某個節點的最短路徑估計值 let predecessor = new Map(); //用來記錄某個節點的前驅節點 // 第一步: 初始化圖 for (let v of vertices) { distance.set(v, Infinity); // 初始化最短估計距離 默認無窮大 predecessor.set(v, null); // 初始化前驅節點 默認為空 } distance.set(source, 0); // 將源節點的最短路徑估計距離 初始化為0 // 第二步: 重復松弛邊 for (let i = 1, len = vertices.length - 1; i < len; i++) { for (let e of edges) { if (distance.get(e.u) + e.w < distance.get(e.v)) { distance.set(e.v, distance.get(e.u) + e.w); predecessor.set(e.v, e.u); } } } // 第三步: 檢查是否有負權回路 第三步必須在第二步后面 for (let e of edges) { if (distance.get(e.u) + e.w < distance.get(e.v)) return null; //返回null表示包涵負權回路 } return { distance: distance, predecessor: predecessor } } var vertices = ["v1", "v2", "v3", "v4"]; var edges = [ {u:"v1", v:"v2", w:1}, {u:"v1", v:"v3", w:3}, {u:"v2", v:"v4", w:5}, {u:"v3", v:"v4", w:1}, {u:"v4", v:"v2", w:-3} ]; var g = Graph(); g.initVertices(vertices); g.initEdges(edges); var r = BellmanFord(g.vertices, g.edges, g.vertices[0]); console.log(r);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90650.html
摘要:最近在上算法課大三,因為自己是寫的,不想用去寫。在網上百度用實現單源點最短路徑動態規劃分段圖算法這兩個算法,發現并沒有。。。 最近在上算法課(大三),因為自己是寫js+php的,不想用c去寫。在網上百度用js實現單源點最短路徑、動態規劃分段圖算法這兩個算法,發現并沒有。。。于是自己xjb寫了下,c里的帶指針的結構體按我的理解換成了對象數組,寫的不好請各位大牛給點改進的建議。。。 動態規...
摘要:由于是從頂點到的最短路徑,則有。算法流程根據最短路徑的最優子結構性質,提出了以最短路徑長度遞增,逐次生成最短路徑的算法。相關文章王者編程大賽之一王者編程大賽之二蓄水池王者編程大賽之三背包王者編程大賽之四約瑟夫環 首發于 樊浩柏科學院 自如年底就會擁有 50W 間房子,大家知道每間房房子都是需要配置完才能出租給自如客的,整個房租的配置過程是很復雜的,每天都需要大量的物流師傅將家電、家具...
摘要:面試算法實踐與國外大廠習題指南翻譯自維護的倉庫,包含了在線練習算法概述與大廠習題實戰等內容。面試算法實踐與國外大廠習題指南在線練習在線面試編程數據結構鏈表即是由節點組成的線性集合,每個節點可以利用指針指向其他節點。 面試算法實踐與國外大廠習題指南 翻譯自 Kevin Naughton Jr. 維護的倉庫 interviews,包含了在線練習、算法概述與大廠習題實戰等內容。筆者發現正好和...
摘要:相關操作就是判斷的不等號符號改反,初始值設為負無窮副本的最短路徑即為原圖的最長路徑。方法是同上面一樣構造圖,同時會添加負權重邊,再將所有邊取反,然后求最短路徑最短路徑存在則可行沒有負權重環就是可行的調度。 Algorithms Fourth EditionWritten By Robert Sedgewick & Kevin WayneTranslated By 謝路云Chapter ...
摘要:動態路由協議基于鏈路狀態路由算法的開放式最短路徑優先協議,廣泛應用在數據中心的協議。基于距離矢量路由算法的針對網絡之間的路由協議,稱為外網路由協議,簡稱每個數據中心都有自己的路由配置。 ????前面例子中,我們都是在一個局域網內折騰。今天就讓我們擴大范圍,在多個局域網甚至到廣闊的互聯網世界中遨游,看看這中間會發生什么。 ????這個過程中,跨網關訪問是我們要了解的第一個內容。 跨網關訪...
閱讀 1200·2021-11-24 11:16
閱讀 3428·2021-11-15 11:38
閱讀 1920·2021-10-20 13:47
閱讀 546·2021-09-29 09:35
閱讀 2192·2021-09-22 15:17
閱讀 1013·2021-09-07 09:59
閱讀 3374·2019-08-30 13:21
閱讀 2904·2019-08-30 12:47