洛谷P4779——记一次Dijkstra算法的做题经历
2021/5/2 12:55:08
本文主要是介绍洛谷P4779——记一次Dijkstra算法的做题经历,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
l老夫最近数据结构学了Dijkstra算法,就想找一题来练习练习。
题目链接:https://www.luogu.com.cn/problem/P4779
这是一道Dijkstra算法的模板题,要求源点s到各店的最短路径长并输出。
起初,我以为这题很简单,不就是堆优化的Dijkstra算法吗?我就提交了如下代码:
1 #include <iostream> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #define maxn 100010 6 using namespace std; 7 struct edge { 8 int to;//有向边的头 9 int w;//边权 10 }; 11 int dist[maxn]; 12 struct cmp { 13 bool operator()(const int &x, const int &y) 14 { 15 return dist[x] > dist[y]; 16 } 17 }; 18 vector<edge>N[maxn]; 19 int n, m, s; 20 21 void dijkstra() 22 { 23 for (int i = 1; i <= n; i++) 24 { 25 dist[i] = 1000000001; 26 } 27 dist[s] = 0; 28 priority_queue<int>q; 29 q.push(s); 30 int v; 31 while (!q.empty()) 32 { 33 v = q.top(); 34 q.pop(); 35 int x; 36 for (int i = 0; i < N[v].size(); i++) 37 { 38 x = N[v][i].to; 39 if (dist[v]+N[v][i].w<dist[x]) 40 { 41 dist[x] = dist[v] + N[v][i].w; 42 q.push(x); 43 44 } 45 } 46 } 47 } 48 int main() 49 { 50 scanf("%d%d%d", &n, &m, &s); 51 int u; 52 edge e0; 53 for (int i = 1; i <= m; i++) 54 { 55 scanf("%d%d%d", &u, &e0.to, &e0.w); 56 N[u].push_back(e0); 57 } 58 dijkstra(); 59 for (int i = 1; i <= n; i++) 60 printf("%d ", dist[i]); 61 return 0; 62 }
然后#1、#6TLE了。
既然用了堆优化还能超时,那一定就是需要剪枝。
然后,我加了一个vis数组,提交了下面的代码:
1 #include <iostream> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #define maxn 100010 6 using namespace std; 7 struct edge { 8 int to;//有向边的头 9 int w;//边权 10 }; 11 int dist[maxn],vis[maxn]; 12 struct cmp { 13 bool operator()(const int &x, const int &y) 14 { 15 return dist[x] > dist[y]; 16 } 17 }; 18 vector<edge>N[maxn]; 19 int n, m, s; 20 21 void dijkstra() 22 { 23 for (int i = 1; i <= n; i++) 24 { 25 dist[i] = 1000000001; 26 } 27 dist[s] = 0; 28 29 priority_queue<int>q; 30 q.push(s); 31 int v; 32 while (!q.empty()) 33 { 34 v = q.top(); 35 q.pop(); 36 //printf("%d\n", v); 37 if (vis[v]) 38 continue; 39 vis[v] = 1; 40 41 int x; 42 for (int i = 0; i < N[v].size(); i++) 43 { 44 x = N[v][i].to; 45 46 if (dist[v]+N[v][i].w<dist[x]) 47 { 48 dist[x] = dist[v] + N[v][i].w; 49 q.push(x); 50 } 51 } 52 } 53 } 54 int main() 55 { 56 scanf("%d%d%d", &n, &m, &s); 57 int u; 58 edge e0; 59 for (int i = 1; i <= m; i++) 60 { 61 scanf("%d%d%d", &u, &e0.to, &e0.w); 62 N[u].push_back(e0); 63 } 64 dijkstra(); 65 for (int i = 1; i <= n; i++) 66 printf("%d ", dist[i]); 67 return 0; 68 }
然后WA了4个点。
这就说明,这个枝剪得有问题。原因在于,我上面这段代码里,每当一个节点从优先队列里出来时,其vis[]为0的邻接节点都会被打上标记、更新dist[]并入队。设其中某个节点为x,则它必然在未来的某个时间点出队并更新其邻接节点;然而,此时dist[x]未必是s到x路径中的最小值,因此,由x更新的它的邻接节点的dist值就可能不是最小值。而由于vis[x]==1,故以后都不可能再由x对其邻接节点进行更新,这就可能导致错误。
于是,我就改变了剪枝的方法。设v为u的邻接节点,对u进行扩展时,用pair<int,int>将v和u、v之间的边权dis一起放入堆中。当v出队时,比较dis和dist[v],若dis<dist[v]则进行扩展,否则就continue,因为在dis>=dist[v]时的扩展操作不会对结果产生影响。代码如下:
1 #include <iostream> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #include <string> 6 #define maxn 100010 7 using namespace std; 8 typedef pair<int, int> my_pair;//stl在Linux下不支持嵌套,所以用typedef将其重新定义为一个数据类型 9 struct edge { 10 int to;//有向边的头 11 int w;//边权 12 }; 13 int dist[maxn]; 14 int vis[maxn]; 15 vector<edge>N[maxn]; 16 int n, m, s; 17 priority_queue<my_pair>pq; 18 void dijkstra() 19 { 20 for (int i = 1; i <= n; i++) 21 { 22 dist[i] = 1000000000+7; 23 24 } 25 dist[s] = 0; 26 27 pq.push(my_pair(-dist[s],s)); 28 int u, dis, v; 29 while (!pq.empty()) 30 { 31 u = pq.top().second; 32 dis = -pq.top().first; 33 pq.pop(); 34 if (dis > dist[u]) 35 continue; 36 for (int i = 0; i < N[u].size(); i++) 37 { 38 v = N[u][i].to; 39 if (dist[u] + N[u][i].w < dist[v]) 40 { 41 dist[v] = dist[u] + N[u][i].w; 42 pq.push(my_pair(-dist[v], v)); 43 } 44 } 45 } 46 } 47 int main() 48 { 49 scanf("%d%d%d", &n, &m, &s); 50 int u; 51 edge e0; 52 for (int i = 1; i <= m; i++) 53 { 54 scanf("%d%d%d", &u, &e0.to, &e0.w); 55 N[u].push_back(e0); 56 } 57 dijkstra(); 58 for (int i = 1; i <= n; i++) 59 printf("%d ", dist[i]); 60 return 0; 61 }
这篇关于洛谷P4779——记一次Dijkstra算法的做题经历的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南