最短路径算法是解决图论中节点之间最短路径问题的经典算法。以下是两种常见的最短路径算法:Dijkstra算法和Floyd-Warshall算法。
Dijkstra算法
Dijkstra算法用于解决单源最短路径问题,即给定一个起点,找到起点到其他所有节点的最短路径。
基本思想:
- 初始化距离数组dist[],将起点到自己的距离设为0,到其余各点的距离设为无穷大(表示不可达)。
- 创建一个集合S,用于存放已找到最短路径的顶点,初始时集合S只包含起点。
- 从未加入S的顶点中选取一个距离起点最近的顶点u,加入S。
- 更新与u相邻的顶点的距离值:如果经过u的路径比原来已知的路径更短,则更新距离值。
- 重复步骤3和4,直到所有顶点都加入S为止。
特点:
- 只能用于非负权重的图。
- 时间复杂度为O(|V|^2),其中|V|是顶点的数量。如果使用优先队列优化,时间复杂度可以降低到O(|V|log|V|+|E|),其中|E|是边的数量。
Floyd-Warshall算法
Floyd-Warshall算法用于解决多源最短路径问题,即找到任意两个顶点之间的最短路径。
基本思想:
- 初始化一个二维数组dist[][],dist[i][j]表示顶点i到顶点j的初始距离(如果i和j之间有直接连边,则为边的权重;否则为无穷大)。
- 对于每一对顶点k和i,更新dist[i][j]为min(dist[i][j], dist[i][k] + dist[k][j]),即考虑经过顶点k的路径是否更短。
- 重复步骤2,直到dist[][]不再发生变化为止。
特点:
- 可以处理负权重的图,但不能处理负权重的环(会导致结果错误)。
- 时间复杂度为O(|V|^3),其中|V|是顶点的数量。因此,对于大型图来说,Floyd-Warshall算法可能不是最高效的选择。
这两种算法在实际应用中都有广泛的应用,根据问题的具体需求和图的特性选择合适的算法非常重要。例如,在需要快速找到单源最短路径的情况下,Dijkstra算法可能更合适;而在需要找到任意两点之间最短路径的情况下,Floyd-Warshall算法可能更合适。
以下是使用C++分别实现Dijkstra算法和Floyd-Warshall算法的示例代码。
Dijkstra算法实现
cpp复制代码
| #include <iostream>  | |
| #include <vector>  | |
| #include <limits>  | |
| #include <queue>  | |
| using namespace std;  | |
| void dijkstra(vector<vector<int>>& graph, int src) {  | |
| int V = graph.size();  | |
| vector<int> dist(V, numeric_limits<int>::max()); // 初始化距离为无穷大  | |
| dist[src] = 0; // 源点距离为0  | |
| priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;  | |
| pq.push({0, src}); // 将源点入队  | |
| while (!pq.empty()) {  | |
| int u = pq.top().second;  | |
| pq.pop();  | |
| for (int v = 0; v < V; ++v) {  | |
| if (graph[u][v] && dist[u] != numeric_limits<int>::max() && dist[u] + graph[u][v] < dist[v]) {  | |
| dist[v] = dist[u] + graph[u][v];  | |
| pq.push({dist[v], v});  | |
| }  | |
| }  | |
| }  | |
| // 打印结果  | |
| cout << "Vertex \t Distance from Source" << endl;  | |
| for (int i = 0; i < V; i++)  | |
| cout << i << "\t\t" << dist[i] << endl;  | |
| }  | |
| int main() {  | |
| int V = 5; // 顶点数量  | |
| vector<vector<int>> graph = {  | |
| {0, 9, 0, 0, 0},  | |
| {9, 0, 6, 0, 0},  | |
| {0, 6, 0, 3, 0},  | |
| {0, 0, 3, 0, 7},  | |
| {0, 0, 0, 7, 0}  | |
| };  | |
| int src = 0; // 源点  | |
| dijkstra(graph, src);  | |
| return 0;  | |
| } | 
Floyd-Warshall算法实现
cpp复制代码
| #include <iostream>  | |
| #include <vector>  | |
| #include <limits>  | |
| using namespace std;  | |
| void floydWarshall(vector<vector<int>>& graph) {  | |
| int V = graph.size();  | |
| // dist[i][j] 将包含i到j的最短距离  | |
| vector<vector<int>> dist(V, vector<int>(V));  | |
| // 初始化dist[][]为图的权重  | |
| for (int i = 0; i < V; i++)  | |
| for (int j = 0; j < V; j++)  | |
| dist[i][j] = graph[i][j];  | |
| // 通过每个顶点作为中间点来更新dist[][]  | |
| for (int k = 0; k < V; k++) {  | |
| // Pick all vertices as source one by one  | |
| for (int i = 0; i < V; i++) {  | |
| // Pick all vertices as destination for the  | |
| // above picked source  | |
| for (int j = 0; j < V; j++) {  | |
| // If vertex k is on the shortest path from i to j,  | |
| // then update the value of dist[i][j]  | |
| if (dist[i][k] + dist[k][j] < dist[i][j])  | |
| dist[i][j] = dist[i][k] + dist[k][j];  | |
| }  | |
| }  | |
| }  | |
| // 打印结果  | |
| cout << "Following matrix shows the shortest distances between every pair of vertices" << endl;  | |
| for (int i = 0; i < V; ++i) {  | |
| for (int j = 0; j < V; ++j) {  | |
| if (dist[i][j] == numeric_limits<int>::max())  | |
| cout << "INF" << "\t";  | |
| else  | |
| cout << dist[i][j] << "\t";  | |
| }  | |
| cout << endl;  | |
| }  | |
| }  | |
| int main() {  | |
| int V = 4; // 顶点数量  | |
| vector<vector<int>> graph = {  | |
| {0, 5, INF, 10},{5, 0, 3, INF},{INF, 3, 0, 1}, {10, INF, 1, 0} }; | 
| // 将INF替换为一个足够大的数,表示无穷大  | |
| const int INF = numeric_limits<int>::max();  | |
| for (auto& row : graph) {  | |
| for (auto& elem : row) {  | |
| if (elem == INF) {  | |
| elem = numeric_limits<int>::max();  | |
| }  | |
| }  | |
| }  | |
| floydWarshall(graph);  | |
| return 0; | 
}
| 在上面的Floyd-Warshall算法实现中,我使用了一个足够大的数(`numeric_limits<int>::max()`)来表示图中不存在的边(即无穷大距离)。这里假设图中不含有负权重的环,因为Floyd-Warshall算法无法正确处理这种情况。  | |
| 请注意,上述代码只是两种算法的简单实现,并没有进行错误处理或优化。在实际应用中,你可能需要考虑更多因素,比如检查输入的有效性、使用更高效的数据结构、处理特殊情况等。  | 
以下是使用Java实现Dijkstra算法和Floyd-Warshall算法的示例代码。
Dijkstra算法实现
java复制代码
| import java.util.*;  | |
| public class Dijkstra {  | |
| public static void main(String[] args) {  | |
| int[][] graph = {  | |
| {0, 5, INF, 10},  | |
| {INF, 0, 3, INF},  | |
| {INF, INF, 0, 1},  | |
| {INF, INF, INF, 0}  | |
| };  | |
| int src = 0; // 源点  | |
| int V = graph.length;  | |
| dijkstra(graph, src, V);  | |
| }  | |
| private static final int INF = Integer.MAX_VALUE;  | |
| public static void dijkstra(int[][] graph, int src, int V) {  | |
| int[] dist = new int[V];  | |
| Arrays.fill(dist, INF);  | |
| dist[src] = 0;  | |
| boolean[] visited = new boolean[V];  | |
| for (int count = 0; count < V - 1; count++) {  | |
| int u = minDistance(dist, visited, V);  | |
| visited[u] = true;  | |
| for (int v = 0; v < V; v++) {  | |
| if (!visited[v] && graph[u][v] != INF && dist[u] != INF && dist[u] + graph[u][v] < dist[v]) {  | |
| dist[v] = dist[u] + graph[u][v];  | |
| }  | |
| }  | |
| }  | |
| printSolution(dist);  | |
| }  | |
| static int minDistance(int dist[], boolean visited[], int V) {  | |
| int min = INF, min_index = -1;  | |
| for (int v = 0; v < V; v++) {  | |
| if (visited[v] == false && dist[v] <= min) {  | |
| min = dist[v];  | |
| min_index = v;  | |
| }  | |
| }  | |
| return min_index;  | |
| }  | |
| static void printSolution(int dist[]) {  | |
| System.out.println("Vertex \t Distance from Source");  | |
| for (int i = 0; i < dist.length; i++) {  | |
| System.out.println(i + "\t\t" + dist[i]);  | |
| }  | |
| }  | |
| } | 
Floyd-Warshall算法实现
java复制代码
| public class FloydWarshall {  | |||||||||||||||
| public static void main(String[] args) {  | |||||||||||||||
| int[][] graph = {  | |||||||||||||||
| {0, 5, INF, 10},  | |||||||||||||||
| {INF, 0, 3, INF},  | |||||||||||||||
| {INF, INF, 0, 1},  | |||||||||||||||
| {INF, INF, INF, 0}  | |||||||||||||||
| };  | |||||||||||||||
| int V = graph.length;  | |||||||||||||||
| floydWarshall(graph, V);  | |||||||||||||||
| }  | |||||||||||||||
| private static final int INF = Integer.MAX_VALUE;  | |||||||||||||||
| public static void floydWarshall(int[][] graph, int V) {  | |||||||||||||||
| int[][] dist = new int[V][V];  | |||||||||||||||
| // 初始化dist[][]为图的权重  | |||||||||||||||
| for (int i = 0; i < V; i++) {  | |||||||||||||||
| for (int j = 0; j < V; j++) {  | |||||||||||||||
| dist[i][j] = graph[i][j];  | |||||||||||||||
| }  | |||||||||||||||
| }  | |||||||||||||||
| // 通过每个顶点作为中间点来更新dist[][]  | |||||||||||||||
| for (int k = 0; k < V; k++) {  | |||||||||||||||
| for (int i = 0; i < V; i++) {  | |||||||||||||||
| for (int j = 0; j < V; j++) {  | |||||||||||||||
| if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {  | |||||||||||||||
| dist[i][j] = dist[i][k] + dist[k][j];  | |||||||||||||||
| }  | |||||||||||||||
| }  | |||||||||||||||
| }  | |||||||||||||||
| }  | |||||||||||||||
| // 打印结果  | |||||||||||||||
| printSolution(dist, V);  | |||||||||||||||
| }  | |||||||||||||||
| static void printSolution(int[][] dist, int V) {  | |||||||||||||||
| System.out.println("Following matrix shows the shortest distances between every pair of vertices");  | |||||||||||||||
| for (int i = 0; i < V; i++) {  | |||||||||||||||
| for (int j = 0; j < V; j++) { 
 
 |