算法思想:
类似最小生成树的贪心算法,从起点 v0 每次新拓展一个距离最小的点,再以这个点为中间点,更新起点到其他点的距离。
算法实现:
需要定义两个一维数组:①vis[ i ] 表示是否从源点到顶点 i 的最短距离。②用d[ i ] 记录源点v0到顶点 i 的距离值。
具体步骤如下:
(1)初始化 d[ v0 ] = 0 ,源点v0到其他点的距离值 d[ i ] = ∞ 。
(2)经过 n 次如下操作,最后得到 v0 到 n 个顶点的最短距离:
①选择一个未标记的点 v 并且 d[ v ] 的值是最小的;
②标记点 v ,即 vis[ v ] = 1;
③以 k 为中间点,修改源点 v0 到其他为标记的点 j 的距离值 d[ j ]。
算法复杂度:
朴素版的复杂度为 O(n2),因为每次查找未标记的节点需耗时 O(n),堆优化后的Dijkstra的复杂度可以降为 O( (n+m) log m )。
算法模板:
①朴素的Dijkstra
#includeusing namespace std;struct Edge//前向星存边{ int to;//此边的子节点 int w;//此边的权值 int next;//与它最近的父节点一样的边的编号}edge[1000000];int head[20000];//以某点为父节点引出的最后一条边int cnt=0;//边编号inline void add(int x,int y,int w)//存边{ cnt++; edge[cnt].to=y; edge[cnt].w=w; edge[cnt].next=head[x]; head[x]=cnt;//更新head}int main(){ bool visit[20000]={ 0};//是否作为过起点 long long dis[20000];//距离 int n,m,s; int x,y,w; scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=n;i++)dis[i]=2147483647; for(int i=0;i dis[curr]+edge[i].w) dis[edge[i].to]=dis[curr]+edge[i].w;//更新操作 } minn=2147483647; for(int i=1;i<=n;i++) { if(!visit[i]&&minn>dis[i])//取新的最小值 { minn=dis[i]; curr=i; } }// } for(int i=1;i<=n;i++)printf("%lld ",dis[i]); return 0;}
②堆优化的Dijkstra
#include#include #include #include #include #include #include #include #include #include #include
巩固:
①
②