圖相關(二)圖的鄰接矩陣表示(C++)及最短路徑演算法
阿新 • • 發佈:2018-12-31
一.Dijikstra演算法
注意:計算最短路徑時,需要把鄰接矩陣中沒有邊的位置初始化為無窮大;此處以INF表示,INF可以取0x3f3f3f3f,不能直接設為INT_MAX(因為做加法時會上溢)。
測試用圖:
其鄰接矩陣表示為:
vector<vector<int>> test_graph(7, vector<int>(7, INF)); test_graph[0][1] = 20; test_graph[0][2] = 50; test_graph[0][3] = 30; test_graph[1][2] = 25; test_graph[1][5] = 70; test_graph[2][3] = 40; test_graph[2][4] = 25; test_graph[2][5] = 50; test_graph[3][4] = 55; test_graph[4][5] = 10; test_graph[4][6] = 70; test_graph[5][6] = 50;
其中INF為:
const int INF = 0x3f3f3f;//不能取得太大(dijikstra中會用到,其餘情況沒邊用0表示即可)
程式碼:
//pre記錄字首 const int INF = 0x3f3f3f;//不能取得太大(dijikstra中會用到,其餘情況沒邊用0表示即可) void dijkstra(graph g, vector<int>& lowcost, vector<int>& pre, int beg) {//第二、三個引數為傳出引數,分別表示從源節點beg,到所有節點的最短路路徑 size_t N = g.cost.size(); vector<bool> visited(N, false); for (size_t i = 0;i < N;++i) {//初始化lowcost和pre lowcost[i] = INF; pre[i] = -1; } lowcost[beg] = 0;//出發點到自己的最短路徑是0 for (size_t i = 0;i < N;++i) { int newNode = -1;//下一個要被選中的點的編號, 初始化為 - 1 int MinWeight=INF;//與當前節點相鄰的邊的最小權值 //第一個for,遍歷所有的未被訪問過的節點,選中間點(已選節點之外的離出發點距離最短的點) for (size_t j = 0;j < N;++j) { if (!visited[j] && lowcost[j] < MinWeight) { MinWeight = lowcost[j]; newNode = j; } } if(-1==newNode) break;//圖不連通時,退出 visited[newNode] = true;//將中間點標記為已訪問狀態 for (size_t j = 0;j < N;++j) { if (!visited[j] && lowcost[newNode] + g.cost[newNode][j] < lowcost[j]){ lowcost[j] = lowcost[newNode] + g.cost[newNode][j]; pre[j] = newNode; } } } }
步驟:
1.初始化時,將出發點到自己的最短路徑置為0,其餘置為無窮
2.對於出發點以外的點(即上面第二個for中所選的點j),考察從出發點直接到它的距離d1=lowcost[j]和先經過一個第一個for所選的中間點(newNode)才到j的距離d2=lowcost[newNode] + g.cost[newNode][j];
3.如果經由中間點然後訪問點j的距離比直接訪問j的距離短,即步驟2中的d2<d1時,更新出發點到j的最短距離為d2,它的上一個節點即那個中間點newNode
測試部分:
graph g; g.cost = test_graph; g.vertex = { "v1","v2","v3","v4","v5","v6","v7" }; vector<int> lowcost(7, 0); vector<int> pre(7, 0); dijkstra(g, lowcost, pre, 0); cout << "從v1其它節點的最短距離分別是: " << endl; for (size_t i = 0;i < g.vertex.size();++i) { cout << g.vertex[i] << ";" << lowcost[i] <<" " ; } cout << endl; cout << endl; cout << "每個節點的前驅是: " << endl; for (size_t i = 0;i < g.vertex.size();++i) { cout << g.vertex[i] << "的前驅是: " << ((pre[i] == -1) ? "null" :g.vertex[pre[i]]) << endl;; }
測試結果: