图的应用——最短路径

{"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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章