檢查圖中兩節點之間給定路徑是否為最短路徑
要檢查圖中兩個節點之間給定路徑是否表示最短路徑,可以將給定路徑上所有邊的權重之和與使用可靠的最短路徑演算法(如 Dijkstra 演算法或 Floyd-Warshall 演算法)計算出的相同節點對之間的最短距離進行比較。如果給定路徑上所有邊權重之和等於最短距離,則它表示最短路徑。否則,如果邊權重之和大於最短距離,則表示圖中兩個節點之間存在更短的路徑。
使用的方法
Dijkstra 演算法
帶邊反轉代價的 Floyd-Warshall 演算法
貪心演算法
Dijkstra 演算法是一種常用的圖遍歷演算法,用於查詢圖中源節點到所有其他節點的最短路徑。在檢查兩個節點之間給定路徑是否表示最短路徑的上下文中,Dijkstra 演算法可用於計算這兩個節點之間的最短距離。透過從起始節點執行 Dijkstra 演算法,我們可以獲得所有其他節點的最短距離。如果給定路徑與這兩個節點之間的最短距離匹配,則它表示有效且最短的路徑。否則,如果給定路徑長於計算出的最短距離,則表示圖中存在更短的路徑。
演算法
建立最短路徑 (圖,源,目標)
初始化一個名為`visited`的集合來儲存已訪問的節點,以及一個名為`distances`的字典來儲存最短距離。
在`distances`字典中,將源節點的距離設定為0,所有其他節點的距離設定為無窮大。
當存在未訪問的節點時:
a. 從`distances`字典中選擇距離最小的節點,並將其標記為已訪問。
b. 對於當前節點的每個相鄰節點:
計算臨時距離,方法是將邊權重新增到當前節點的距離。
如果臨時距離小於儲存的距離,則更新距離。
如果`distances`中從源到目標的最短距離等於給定路徑長度,則返回 true(給定路徑表示最短路徑)。否則,返回 false。
此演算法使用 Dijkstra 方法計算最短距離,然後將從源到目標的最短距離與給定路徑長度進行比較,以確定它是否表示最短路徑。
示例
#include <iostream> #include <vector> #include <queue> #include <limits> using namespace std; const int INF = numeric_limits<int>::max(); bool shortestPath(vector<vector<pair<int, int>>>& graph, int source, int destination, int pathLength) { int numNodes = graph.size(); vector<int> distances(numNodes, INF); distances[source] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.emplace(0, source); while (!pq.empty()) { int u = pq.top().second; int dist = pq.top().first; pq.pop(); if (dist > distances[u]) continue; for (auto& neighbor : graph[u]) { int v = neighbor.first; int weight = neighbor.second; if (dist + weight < distances[v]) { distances[v] = dist + weight; pq.emplace(distances[v], v); } } } return (distances[destination] == pathLength); } int main() { int numNodes = 6; vector<vector<pair<int, int>>> graph(numNodes); // Build the graph graph[0].emplace_back(1, 2); graph[0].emplace_back(2, 5); graph[1].emplace_back(3, 4); graph[1].emplace_back(4, 1); graph[2].emplace_back(3, 2); graph[3].emplace_back(4, 3); graph[3].emplace_back(5, 6); graph[4].emplace_back(5, 2); int source = 0; int destination = 5; int pathLength = 8; bool isShortestPath = shortestPath(graph, source, destination, pathLength); if (isShortestPath) cout << "The given path represents a shortest path." << endl; else cout << "The given path does not represent a shortest path." << endl; return 0; }
輸出
The given path does not represent a shortest path.
帶邊反轉代價的 Floyd-Warshall 演算法
Floyd-Warshall 演算法是一種動態規劃演算法,用於查詢圖中所有節點對之間的最短路徑。在檢查兩個節點之間給定路徑是否表示最短路徑的上下文中,Floyd-Warshall 演算法可用於計算圖中所有節點對之間的最短距離。透過將使用該演算法獲得的最短距離與給定路徑上所有邊權重之和進行比較,我們可以確定給定路徑是否表示最短路徑。如果邊權重之和等於最短距離,則給定路徑可能是圖中這兩個節點之間的最短路徑。
演算法
建立一個大小為 numNodes x numNodes 的二維陣列,並將其所有節點對初始化為無窮大 (INF)。
將 dist 的對角線元素設定為 0。
對於圖中每個帶權重 w 的有向邊 (u, v),將 dist[u][v] 更新為 w,並將 dist[v][u] 更新為 w_reversal,其中 w_reversal 是邊 (v, u) 的反向權重。
使用以下巢狀迴圈執行 Floyd-Warshall 演算法:
對於每個中間節點 k,從 numNodes 到 1,執行以下操作:
對於每對節點 i 和 j,從 numNodes 到 1,將 dist[i][j] 更新為以下最小值:
dist[i][j]
dist[i][k] + dist[k][j]
演算法結束後,dist 將包含所有節點對之間的最短距離,考慮了邊反轉代價。
要檢查給定路徑(源和目標節點之間)是否表示最短路徑,請將給定路徑的長度與 distance[source][destination] 進行比較。如果它們相等,則給定路徑表示最短路徑。
示例
#include <iostream> #include <vector> using namespace std; const int INF = 1e9; void floydWarshall(vector<vector<int>>& graph, int numNodes) { vector<vector<int>> dist(graph); // Distance matrix initialized with the graph for (int k = 0; k < numNodes; k++) { for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numNodes; j++) { dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); } } } // Printing the shortest distances cout << "Shortest distances between all pairs of nodes:" << endl; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numNodes; j++) { if (dist[i][j] == INF) cout << "INF "; else cout << dist[i][j] << " "; } cout << endl; } } int main() { int numNodes = 4; // Number of nodes // Adjacency matrix representation of the graph with edge weights and edge reversal costs vector<vector<int>> graph = { {0, 5, INF, 10}, {INF, 0, 3, INF}, {INF, INF, 0, 1}, {INF, INF, INF, 0} }; floydWarshall(graph, numNodes); return 0; }
輸出
Shortest distances between all pairs of nodes: 0 5 8 9 INF 0 3 4 INF INF 0 1 INF INF INF 0
結論
本文探討了如何檢查圖中兩個節點之間給定路徑是否表示最短路徑。它解釋了兩種方法:Dijkstra 演算法和帶邊反轉代價的 Floyd-Warshall 演算法。C 程式碼示例說明了這些演算法。它還簡要解釋了這些演算法及其應用。本文旨在幫助讀者理解在圖中查詢最短路徑的概念,並確定給定路徑是否確實是最佳路徑。