圖的應用——最短路徑

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"最短路徑","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"典型用途:交通問題。如:城市A到城市B有多條線路,但每條線路的交通費(或所需時間)不同,那麼,如何選擇一條線路,使總費用(或總時間)最少?","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"問題抽象:在","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"帶權有向圖","attrs":{}},{"type":"text","text":"中A點(源點)到達B點(終點)的多條路徑中,尋找一條各邊權值之和最小的路徑,即最短路徑。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最短路徑與最小生成樹不同,路徑上不一定包含n個頂點","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"兩種常見最短路徑問題","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Dijkstra(迪傑斯特拉)算法 —— 單源最短路徑","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fe/fe0ccf13037831979c1960ac9ae9f9eb.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"算法思想","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把圖中頂點集合分成兩組:","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第一組爲已求出其最短路徑的頂點集合S","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第二組爲尚未確定最短路徑的頂點集合U","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"初始時,S只包含源點,S={v},U包含除v外的其他頂點;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"從U中選取一個距離最小的頂點k,把k加入到S中;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"以k作爲新考慮的中間點,修改U中各頂點的距離;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"重複步驟 2、3 直到所有頂點都包含在S中","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"算法實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}},{"type":"strong","attrs":{}}],"text":"算法流程圖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f4/f485a7f264f2dc4ae20f3f22d682e786.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}},{"type":"strong","attrs":{}}],"text":"C++代碼實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"void ShortestPath_DIJ(AMGraph G, int v0){\n // 用Dijkstra算法求有向網G的v0頂點到其餘頂點的最短路徑 \n n = G.vexnum; // G 中頂點個數\n for(v = 0; v < n; v++){\n // n 個頂點依次初始化\n S[v] = false; // S 初始爲空集\n D[v] = G.arcs[v0][v]; // 將v0到各個終點的最短路徑長度初始化 \n if(D[v] < MaxInt) Path[v] = v0; // v0和v之間有弧,將v的前驅置爲v0\n else Path[v] = -1; // 如果v0和v之間無弧,則將v的前驅置爲-1\n }\n S[v0] = true; // 將v0加入S\n D[v0] = 0; // 源點到源點的距離爲0\n\n /*―開始主循環,每次求得v0到某個頂點v的最短路徑,將v加到S集―*/\n for(i = 1; i < n; i++){\n // 對其餘n-1個頂點,依次進行計算\n min = MaxInt;\n for(w = 0; w < n; w++)\n if(!S[w] && (D[w] < min)){\n v = w;\n min = D[w]; // 選擇一條當前的最短路徑,終點爲v\n }\n S[v] = true; // 將v加入S\n for(w = 0; w < n; w++) // 更新從v0出發到集合V−S上所有頂點的最短路徑長度\n if(!S[w] && ((D[v] + G.arcs[v][w]) < D[w])){\n D[w] = D[v] + G.arcs[v][w]; // 更新D[w]\n Path[w] = v; // 更新w的前驅爲v\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule","attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Floyd(弗洛伊德)算法 —— 所有頂點間的最短路徑","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每一對頂點之間的最短路徑方法一:每次以一個頂點爲源點,重複執行Dijkstra算法n次—— T(n)=O(n³)方法二:弗洛伊德(Floyd)算法算法思想:逐個頂點試探法","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"算法思想","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"初始時設置一個n階方陣,令其對角線元素爲0,若存在弧,則對應元素爲權值;否則爲∞","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"逐步試着在原直接路徑中增加中間頂點,若加入中間點後路徑變短,則修改之","attrs":{}},{"type":"text","text":";否則,維持原值。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有頂點試探完畢,算法結結束","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/22/229dcce75064d72a5fb540ce68c790c2.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"算法實現","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"typedef int Pathmatirx[MAXVEX][MAXVEX]\ntypedef int ShortPathTable[MAXVEX][MAXVEX]\n\n/*- Floyd算法,求網圖G中各頂點v到其餘頂點w最短路徑P[v][w]及帶權長度D[v][w] -*/\nvoid ShrotestPath_Floyd(MGraph G, Pathmatirx* P, ShortPathTable* D){\n int v, w, k;\n for(v = 0; v < G.numVertexes; ++v){\n // 初始化D與P\n for(w = 0; w < G.numVertexes; ++w){\n (*D)[v][w] = G.matirx[v][w]; // D[v][w]值即爲對應點間的權值\n (*P)[v][w] = w; // 初始化P\n\n }\n }\n\n for(k = 0; k < G.numVertexes; ++k)\n for(v = 0; v < G.numVertexes; ++v)\n for(w = 0; w < G.numVertexes; ++w)\n if((*D)[v][w] > (*D)[v][k] + (*D)[k][w]){\n // 如果經過下標爲k頂點路徑比原兩點間路徑更短\n // 將當前兩點間權值設爲更小的一個\n (*D)[v][w] = (*D)[v][k] + (*D)[k][w];\n (*P)[v][w] = (*P)[v][k]; // 路徑設置爲經過下標爲k的頂點\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章