最短路复习(Floyd与Dijkstra)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/suxuyu01/article/details/79945946

理论上来说,现在只会SPFA基本上就够NOIp用了,但是还是忍不住重新复习了一下。。。


Dijkstra算法

该算法仅用于无负权边的图,在稠密图(边数m接近于n^2的图,网格图就是一种非常稠密的图,相对的,稀疏图就是m远小于n^2的图)中的表现比较优秀,可以用邻接表也可以用邻接矩阵。

算法主体


算法也不算难,核心就是松弛操作,朴素的Dijkstra算法的时间复杂度为O(n^2)
①伪代码

清除所有点的标记(flag[i]=0)
dis[s]=0,其他dis[i]=INF      //s为起点的序号
循环n次{                      //n为结点数
  在所有未标记的结点中选出dis最小的结点x
  标记x(flag[x]=1)
  对从x出发的所有边V(x,y),更新dis[y]=min{dis[y],dis[x]+V(x,y).w}
}
②打印路径
省空间费时间方案

与dp中的方案打印一样:从重点出发,一直顺着d[i]+V(i,j).w==d[j]的路径回退到起点

省时间费空间方案

改一下松弛的写法,在松弛的同时在另一个数组记录下前驱结点

if(dis[x]+V(x,y).w<dis[y])
{
    pre[y]=x;
    dis[y]=dis[x]+V(x,y).w;
}

③堆优化

不难看出每次挑选点的过程占了时间复杂度的一个阶位之多,每次挑选出dis最小值,那么我们就可以考虑维护一个小根堆来加速这个算法中选结点的过程
这个小根堆每次松弛完一个点的所有边之后要更新一下,去掉标记过的点,更新结点的dis值,由此不难得出时间复杂度为O((n+m)logn)

Floyd

动态规划算法…深入理解挺困难的,但是代码真的短…
时间复杂度是O(n^3),应用于多源最短路,存图用邻接矩阵

①初始化

#define For(i,l,r) for(int i=l;i<=r;++i)
memset(dis,INF,sizeof dis);//INF不能太大也不能太小,太大会溢出,太小就。。
For(i,1,n)
 dus[i][i]=0;

然后有向边就是dis[from][to]=val
无向边就是两条有向边

②算法主体

For(k,1,n)
 For(i,1,n)
  For(j,1,n)
   dis[i][j]=min{dis[i][j],dis[i][k]+dis[k][j]};

③判联通

首先改一下预处理的方式

memset(dis,0,sizeof dis);
For(i,1,n)
 dis[i][i]=1;

然后边就是dis[from][to]=1
算法部分的处理语句改为

dis[i][j]=dis[i][j]||(dis[i][k]&&dis[k][j]);

好像叫“传递闭包”。。。迷。。。

DFS-SPFA

主要是用于判负环
有个比较简单的练手题
P2850 【[USACO06DEC]虫洞Wormholes】
我的下一篇博客应该就是这个的题解了。。。所以这里就不说了

BFS-SPFA

是Bellman-Ford的队列优化,松弛了一个点之后,继续松弛这个点能到达的所有结点,一直到队列空了
存在负环的时候不存在最短路,这个应该是显然的
模板题
P1339 [USACO09OCT]热浪Heat Wave
P3371 【模板】单源最短路径

很常用的算法,复杂度是O(ke),k一般是2,e是边数,最坏情况是O(nm)

阅读更多

没有更多推荐了,返回首页