Dijkstra是我学会的第一个最短路算法,为什么不先去学SPFA呢?因为我在luogu上翻到了一张比较神奇的图:
关于SPFA
-它死了
以及网上还有各位大佬的经验告诉我:SPFA这玩意很容易被卡。
于是我就决定学习Dijkstra
结构体存边(链式前向星)+优先队列(堆)+Dijkstra求最短路
详细解析都在代码里。
下面附上代码
1 //2019.08.14 XYYXP第一次写dijkstra最短路算法 于中山纪念中学 2 //模板题:Luogu P3371,P4779 3 #include <cstdio> 4 #include <queue> 5 #include <algorithm> 6 #define rr register 7 using namespace std; 8 const int inf = 2147483647; 9 int n,m,s,head[500005],tot,dis[100005],used[100005]; 10 //定义全局变量和最大值(inf) 11 struct Edge{ 12 int nxt,to,length; 13 }edge[500005]; 14 //用结构体存边,nxt表示这条边起点连着的上一条边,to表示这条边通往哪个点,length表示边权 15 struct state { 16 int val, pos; 17 18 bool operator < (const state &tmp) const 19 { 20 return val > tmp.val; 21 } 22 //重载运算符(重载小于号成大于号,用于大根堆变小根堆) 23 }; 24 //定义一个结构体存点,pos表示当前点编号,val表示当前点到起点的最短路长度 25 state makestate(int _pos,int _val) 26 { 27 state tmp; 28 tmp.pos=_pos; 29 tmp.val=_val; 30 return tmp; 31 } 32 //一个结构体函数,新建一个state类型的结构体 33 void add(int x,int y,int z) 34 { 35 tot++; 36 edge[tot].to=y; 37 edge[tot].nxt=head[x]; 38 edge[tot].length=z; 39 head[x]=tot; 40 } 41 //加边函数,表示x到y之间有一条权值为z的边 42 priority_queue <state> heap; 43 //新建一个优先队列(STL库函数) 44 void dijkstra(int st) 45 { 46 for(rr int i=1;i<=n;i++) 47 dis[i]=inf; 48 //初始化起点到各个点的最短路为inf 49 dis[st]=0; 50 heap.push(makestate(st,dis[st])); 51 //初始化起点,起点入队 52 while(!heap.empty()) 53 { 54 int u = heap.top().pos; 55 heap.pop(); 56 //取出优先队列中最小的点,用来更新最短路 57 if(used[u]) 58 continue; 59 used[u]=true; 60 //判断和标记当前点是否被已经用来更新过 61 for(rr int i=head[u];i;i=edge[i].nxt) 62 { 63 int &v=edge[i].to; 64 //引用 v=edge[i].to; 65 if(dis[v] > dis[u]+edge[i].length) 66 { 67 dis[v] = dis[u]+edge[i].length; 68 //更新最短路 69 heap.push(makestate(v,dis[v])); 70 //将更新完的最短路入队 71 } 72 } 73 } 74 } 75 76 int main() 77 { 78 int x,y,z; 79 scanf("%d %d %d",&n,&m,&s); 80 for(rr int i=1;i<=m;i++) 81 { 82 scanf("%d %d %d",&x,&y,&z); 83 add(x,y,z); 84 } 85 //读入并建边 86 dijkstra(s); 87 //调用dijkstra算法函数求单源最短路 88 for(rr int i=1;i<=n;i++) 89 printf("%d ",dis[i]); 90 //输出起点到各点的最短路 91 }
The End