Dijkstra,基础题,借此题好好地复习了之前的算法,Dijkstra是贪心算法的最好例子。
总结一下,Dijkstra算法是将顶点分为两组,一组S表示已经找到最短路径的顶点集合,一组Q表示还未确定是最短路径的顶点集合,维护一个D[n]的数组来记录顶点src到每个顶点的最短路径,该数组在算法完成之前或到达目标顶点前所保存的只是当前情况下的最短路径,当算法完成跳出循环后,D[i]代表点src到点i的最短距离。
算法的过程就是不断更新D[n]数组的过程,首先初始化D[n]为无限大,并将起点src加入集合S,将D[s]设为0,扫描所有与src邻接的点j,并更新D[j]=min(D[j],D[src]+len(src,j)),这个操作一般称作为release(松散操作)。接着从Q中D[i]最小的顶点找出来放入S,继续执行上一步类似的操作,进入循环,直到Q为空。
这时D中保存即为最短路径的值。如果希望记录最短路径,那么可以再维护一个前缀数组P[n]。
这是一基本的Dijkstra算法,算法复杂度O(n2)但是可以通过堆优化算法,使得算复杂度降低到O((m+n)*logn)。
下面直接贴一下堆优化的算法:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 7 #define IFINITY 0x7fffffff 8 #define MAXN 100005 9 10 int D[MAXN]; 11 bool Qv[MAXN]; 12 int N, M, S, T; 13 vector<pair<int, int>> Map[MAXN]; 14 15 int Dijkstra() { 16 priority_queue<pair<int, int>> q; 17 18 for (int i = 1; i <= N; ++i) D[i] = IFINITY; 19 20 D[S] = 0; 21 q.push(make_pair(-D[S], S)); 22 23 while (!q.empty()) { 24 int u = q.top().second; q.pop(); 25 if (u==T) break; 26 if (Qv[u]) continue; 27 Qv[u] = true; 28 29 for (int i = 0; i < Map[u].size(); ++i) { 30 int uvLen, v; 31 v = Map[u][i].first; 32 uvLen = Map[u][i].second; 33 if (D[v] > D[u] + uvLen) { 34 D[v] = D[u] + uvLen; 35 q.push(make_pair(-D[v], v)); 36 } 37 } 38 } 39 40 return D[T]; 41 } 42 43 int main() 44 { 45 int u, v, length; 46 scanf("%d%d%d%d", &N, &M, &S, &T); 47 for (int i = 1; i <= M; ++i) { 48 scanf("%d%d%d", &u, &v, &length); 49 Map[u].push_back(make_pair(v, length)); 50 Map[v].push_back(make_pair(u, length)); 51 } 52 53 printf("%d\n", Dijkstra()); 54 return 0; 55 }
时间: 2024-10-11 13:34:21