\(dijkstra\)怎么写:首先,是和\(SPFA\)同样的初始化。而后,把起点标记为访问。而后更新与其相连的点的最短路的值(就是松弛)。再找到未访问的点中最短路的值最小的点,重复以上操做。
具体实现起来就是这个亚子:
(图片来源于洛谷2019夏令营的课件)
讲完基础的,再来说一下细节问题:这个细节决定了时间复杂度!
这个细节就是“找到未访问的点中最短路的值最小的点”。
两种方法:
第一种:很是实用的爆扫。时间复杂度是O(\(n^2\)),我的感受和\(SPFA\)没有什么区别,不建议使用。
第二种:优先队列!该方法是当一个点的最短路的值被更新后,就将其加入小根堆。这时小根堆里会出现多个相同的点。可是咱们用过一个点以后就会将其标记,因此不会有问题。时间复杂度是O(mlogn)
什么?你不知道小根堆是什么?戳这里
但咱们是不会手打小根堆的,太麻烦了。因而,咱们就要用到priority_queue
。他是系统自带优先队列,可是是大根堆。并且咱们是要按照每一个点的值来排序的。但咱们同时也要记录他的编号。node
因而能够这样搞:spa
struct node { int first,second; friend bool operator<(node x,node y){return x.first>y.first;} }; priority_queue<node> q;
全部问题都解决了,那么上代码吧。code
#include<queue> #include<cstdio> #include<cstring> using namespace std; int n,m,s; int v[100005]; bool f[100005]; struct node { int first,second; friend bool operator<(node x,node y){return x.first>y.first;} }; priority_queue<node> q; struct graph { int tot; int hd[100005]; int nxt[200005],to[200005],dt[200005]; void add(int u,int v,int w) { tot++; nxt[tot]=hd[u]; hd[u]=tot; to[tot]=v; dt[tot]=w; return ; } }g; int main() { scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); g.add(u,v,w);//建图 } memset(v,0x3f,sizeof(v));//初始化 q.push((node){0,s});//压入起点 v[s]=0; while(!q.empty()) { int xx=q.top().second; q.pop(); if(!f[xx])//判断是否被访问过 { f[xx]=true;//标记一下 for(int i=g.hd[xx];i;i=g.nxt[i]) if(v[g.to[i]]>v[xx]+g.dt[i])//松弛 { v[g.to[i]]=v[xx]+g.dt[i]; q.push((node){v[g.to[i]],g.to[i]});//加入小根堆 } } } for(int i=1;i<=n;i++) printf("%d ",v[i]); return 0; }