Dijkstra算法
Posted mr94kevin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dijkstra算法相关的知识,希望对你有一定的参考价值。
Dijkstra算法是用于求单源最短路的算法,也就是求出一个点到图上其他点的最短路,但是要求图中不能有负边权,时间复杂度为O(n2)。
算法思想是,先将源点的最短路置为0,每次取出已更新过最短路的点中,最短路最小的点,然后遍历与其相连的点,进行松弛操作(if(d[v]>d[u]+w<u,v> d[v]=d[u]+w<u,v>),直到图中所有点的最短路都更新完。
显然算法可以优化,就是在取出最短路最小的点时,可以使用堆优化,复杂度大致降到O(mlogn),堆优化的Dijkstra是单源最短路无负边权时很好的选择,不会像SPFA那样被卡。
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int inf=0x3f3f3f3f; int n,m,s,eid,head[maxn],d[maxn],vis[maxn]; struct node { //自定义结构体,用于储存点的编号及其最短路 int n,d; node(int n,int d):n(n),d(d) {} bool operator < (const node& rhs) const { //重载小于运算符,使得优先队列中 return d>rhs.d; //最短路小的先出队 } }; priority_queue<node> q; struct edge { //使用邻接表来储存图 int v,w,next; edge(int v=0,int w=-1):v(v),w(w) {} } E[maxm]; void init() { //记得初始化,包括邻接表的初始化和将d数组原先都置为inf memset(head,-1,sizeof(head)); memset(d,inf,sizeof(d)); } void insert(int u,int v,int w) { E[eid]=edge(v,w); E[eid].next=head[u]; head[u]=eid++; } void dijkstra() { d[s]=0; //先将源点最短路置为0,并入队 q.push(node(s,0)); while(!q.empty()) { node i=q.top(); q.pop(); int u=i.n; if(vis[u]) continue; //每个结点只有一次会被用来更新其他结点 vis[u]=1; //vis标志可避免结点重复扩展 for(int p=head[u];p+1;p=E[p].next) { //遍历相连的结点 int v=E[p].v; if(d[v]>d[u]+E[p].w) { //进行松弛操作,并将更新的结点入队 d[v]=d[u]+E[p].w; q.push(node(v,d[v])); } } } } int main() { scanf("%d%d%d",&n,&m,&s); init(); int u,v,w; for(int i=1;i<=m;++i) { scanf("%d%d%d",&u,&v,&w); insert(u,v,w); } dijkstra(); for(int i=1;i<=n;++i) { if(i!=1) putchar(‘ ‘); printf("%d",d[i]); } return 0; }
需要注意的是,优先队列并不能动态修改结点的优先级(在此处就是最短路d),只能将新更新的结点入队,因此可能出现重复入队的情况。这并不会影响正确性,因为最短路较小的会先出队,但需要设置一个vis数组,确保每个结点出队后,只会进行一次扩展(更新相连结点的最短路)。
以上是关于Dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章
Dijkstra算法A*算法D*算法LPA*算法和D* Lite算法详解汇总(原理matlab代码)格栅地图