【Dijkstra】最短路径
复习笔记【一】 Dijkstra算法
算法核心:对边的松弛
概述:Dijkstra用于求一个点到其他点的最短路径,不适合于负边权,用了贪心思想,复杂度为O(N^2), 与SPFA相比其优点是经堆优化后Dijkstra的时间复杂度为O(NlogN),和最小生成树Prim算法长的很像...
理解:假设我们要计算从一号点出发,一号点到其他点的最短路径。首先,定义一个一维数组distance,distance[J]表示从1号点到J号点的初始路程,假如说两点之间没有边,那我们就假设其两点间的初始路程为正无穷,因为两点可能永远无法到达~
此时distance中存储了一号点到各顶点的距离(假如说有边的话就是边权, 没边就是正无穷)
假如说对于如下数据:
4 4 //四个顶点四条边
1 2 3
1 3 6
2 3 1
2 4 2
| distance[i] | i = 1 | i = 2 | i = 3 | i = 4 |
| value | 0 | 3 | 6 | 无穷大 |
显然,其到自身的距离为0。
1号点与2号点间有边相连,其边权为3
同理:distance[1][3] = 6
Edge[1][4]不存在, distance[1][4] = 正无穷
此时选取其中最小的distance, 这就是1号结点到被选取的这个点的最短路径了,
distance[2] = 3,所以 到 2号结点的最短距离为3, 因为不可能通过第二条边来让其到1号结点的距离更近(仔细想..)
此时再遍历与2号结点相连的边,如果1号结点到k号结点的距离 > 1号结点的距离到2号结点的距离 + 2号结点到k号结点的距离就更新distance,再然后,选取distance中最小的(可以用堆优化的地方),再以最小的点进行遍历....
总结:
1.初始化distance数组和标记数组
for (int i = 1; i <= n; i++) { distance[i] = edge[1][i]; //edge[1][I]为邻接矩阵存储方式 flag[i] = false; //表示i号结点是否已经被标记为最短路,防止重复遍历 } flag[1] = true;
2.核心语句
for (int i = 1, min, u; i <= n - 1; i++) { min = 0x7fffffff; for (int j = 1; j <= n; j++) { if (!flag[[j] && distance[j] < min) { min = distance[j]; //选取最小的distance u = j; } } flag[u] = true; for (int k = 1; k <= n; k++) { //如果有边 if (edge[u][v] < 0x7fffffff) { if (distance[v] > distance[u] + edge[u][v]) { distance[v] = distance[u] + edge[u][v] } } } } for (int i = 1; i <= n; i++) { printf ("%d ", distance[i]); }
完整代码
#include <cstdio> #include <queue> #include <limits.h> #define maxn 1005 struct Node { int diktc; bool visited; struct Edge* edges; bool operator () (const Node *a, const Node *b) { return a->diktc > b->diktc; } Node () : diktc (INT_MAX) , visited (false) {} } nodes[maxn]; struct Edge { int weight; Node* to; Edge* next; Edge () {} Edge (int w, Node* t) : weight (w), to(t) {} }; inline void EdgeMaker (const int &u, const int &v, const int &w) { Edge* curEdge = new Edge(w, nodes + v); curEdge->next = nodes[u].edges; nodes[u].edges = curEdge; } inline void EdgeDestory (const int& n) { for (int i = 0; i < n; i++) { Edge* curEdge = nodes[i].edges; while (curEdge != NULL) { Edge* tmp = curEdge; curEdge = curEdge->next; delete[] tmp; } } } int n, m; inline void Dijkstra (const int &start) { std::priority_queue<Node*, std::vector<Node*>, Node > pq; Edge *curEdge = nodes[start].edges; while (curEdge != NULL) { curEdge->to->diktc = curEdge->weight; pq.push (curEdge->to); curEdge = curEdge->next; } nodes[start].diktc = 0; nodes[start].visited = true; for (int i = 0; i < n; i++) { pq.push (nodes + i); } for (int i = 0, u; i < n - 1; i++) { while (pq.top()->visited) { pq.pop(); } u = pq.top() - nodes; pq.pop(); nodes[u].visited = true; curEdge = nodes[u].edges; while (curEdge != NULL) { if (curEdge->to->diktc > nodes[u].diktc + curEdge->weight) { curEdge->to->diktc = nodes[u].diktc + curEdge->weight; pq.push (curEdge->to); } curEdge = curEdge->next; } } for (int i = 1; i <= n; i++) { printf ("%d ", nodes[i].diktc); } printf ("\n"); } int main () { scanf("%d %d", &n, &m); for (int i = 0, u, v, w; i < m; i++) { scanf ("%d %d %d", &u, &v, &w); EdgeMaker (u, v, w); // EdgeMaker (v, u, w); } Dijkstra (1); EdgeDestory (n); return 0; }

浙公网安备 33010602011771号