面试折在了dijsktra algorithm上,我一个暴风哭泣……
本来是想复习一下Dijsktra算法,又看到了Prim's algorithm 等系列,今天就着这个机会都好好复习一下。
---------------------------正文分割线------------------------------------------
Dijsktra Algorithm
给出一个图以及一个起点,找到从起点到其他所有点的最短路径。
Dijsktra 与 Prim 最小生成树算法类似, 也生成SPT(shortest path tree)并将给定起点作为根节点。
我们维护两个集合,一个集合维护在SPT中的节点S1,另一个集合维护还没有被包含在SPT中的节点S2,在本算法的每一步,我们从S2中找到距根节点最近的点。
以下为使用Dijsktra算法来在给定图中找到起点节点到其他所有节点最短路径的具体步骤:
1.建立SptSet来存储SPT中的树中的节点,并且记录从根节点到这些节点的最短距离。初始化事,该集合为空
2. 给图中的除起点外的每一个节点一个无穷大的初始距离值,起点初始距离为0,这样我们可以最先选择它并从它开始(实现起点)。
3.(while)当SptSet没有图中存储所有的点时:
a. 选择不在SptSet中并且离起点有最短距离的点u
b. 将u加入到SptSet中
c. 更新u所有邻接点的距离。为了更新距离,遍历所有的邻接点。对每一个邻接点v,如果从起点到u的值的总和加上u-v的权重 小于 v点现在的距离值,此时我们更新v的距离值。
举例说明
现在我们初始化距离值:{0, INF, INF, INF, INF, INF, INF, INF, INF},此时SptSet为空:{}
当前我们选择0点并且将其加入SptSet:{0}, 并且更新与0点邻接的点的距离 {4, 8, INF, INF, INF, INF, INF, INF}
选择此时距离原点最近的点,并且将其加入SptSet,然后更新距离
此时SptSet:{0, 1} 距离:{8, 12, INF, INF, INF, INF, INF, INF}
选择此时7距原点最近,加入SptSet并且更新距离值:
SptSet:{0, 1, 7} 距离:{9, 12, 15, INF, INF, INF}
此时6距0最近,加入SptSet并且更新距离值
SptSet: {0, 1, 7, 6} 距离: {11, 12, 15, INF, INF}
此时5距0最近,加入SptSet并且更新距离
SptSet: {0, 1, 7, 6, 5}
直至最后形成最小生成树:
实现:
// A C++ program for Dijkstra's single source shortest path algorithm. // The program is for adjacency matrix representation of the graph #include <stdio.h> #include <limits.h> // Number of vertices in the graph #define V 9 // A utility function to find the vertex with minimum distance value, from // the set of vertices not yet included in shortest path tree int minDistance(int dist[], bool sptSet[]) { // Initialize min value int min = INT_MAX, min_index; for (int v = 0; v < V; v++) if (sptSet[v] == false && dist[v] <= min) min = dist[v], min_index = v; return min_index; } // A utility function to print the constructed distance array int printSolution(int dist[], int n) { printf("Vertex Distance from Source\n"); for (int i = 0; i < V; i++) printf("%d tt %d\n", i, dist[i]); } // Function that implements Dijkstra's single source shortest path algorithm // for a graph represented using adjacency matrix representation void dijkstra(int graph[V][V], int src) { int dist[V]; // The output array. dist[i] will hold the shortest // distance from src to i bool sptSet[V]; // sptSet[i] will true if vertex i is included in shortest // path tree or shortest distance from src to i is finalized // Initialize all distances as INFINITE and stpSet[] as false for (int i = 0; i < V; i++) dist[i] = INT_MAX, sptSet[i] = false; // Distance of source vertex from itself is always 0 dist[src] = 0; // Find shortest path for all vertices for (int count = 0; count < V-1; count++) { // Pick the minimum distance vertex from the set of vertices not // yet processed. u is always equal to src in the first iteration. int u = minDistance(dist, sptSet); // Mark the picked vertex as processed sptSet[u] = true; // Update dist value of the adjacent vertices of the picked vertex. for (int v = 0; v < V; v++) // Update dist[v] only if is not in sptSet, there is an edge from // u to v, and total weight of path from src to v through u is // smaller than current value of dist[v] if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u]+graph[u][v] < dist[v]) dist[v] = dist[u] + graph[u][v]; } // print the constructed distance array printSolution(dist, V); } // driver program to test above function int main() { /* Let us create the example graph discussed above */ int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, {0, 8, 0, 7, 0, 4, 0, 0, 2}, {0, 0, 7, 0, 9, 14, 0, 0, 0}, {0, 0, 0, 9, 0, 10, 0, 0, 0}, {0, 0, 4, 14, 10, 0, 2, 0, 0}, {0, 0, 0, 0, 0, 2, 0, 1, 6}, {8, 11, 0, 0, 0, 0, 1, 0, 7}, {0, 0, 2, 0, 0, 0, 6, 7, 0} }; dijkstra(graph, 0); return 0; }
参考资料:https://www.geeksforgeeks.org/greedy-algorithms-set-6-dijkstras-shortest-path-algorithm/