Dijkstra和Floyd算法

Floyd算法:
  如果要求所有两结点间的最短路径,则可以使用dijkstra算法n次完成,时间复杂度是
O(n^3)
Floyd还提出过另一个算法,同样是O(n^3)的复杂度,但形式上更简单些。
  要求的解是一个矩阵S[N][N],其中S[i][j]表示结点ij的最短路径,算法很像动态
规划算法,甚至更简单些,不同的是这里规划的是一个矩阵,而不是简单的数组。
  Floyd算法过程描述如下:

(在整个循环结束后,S[i][j]肯定是ij之间的最短路径——i如果和j之间有直接通路,但是比S[i][k]+S[k][j]长的话就会被S[i][k]+S[k][j]替换,而S[i][k](或S[k][j])可能也是中间经过某一个其他点(这边设为w点)而得到的ik的最短路径,所以可能ij的最短路径是由S[i][k]+S[k][j]得到,而S[i][k]又是由iw再到k的(S[k][j]同理),因此ij的最短路径就可能是i>w>k>j的(这边假设S[k][j]中间没有经过其他点,自己就是最短的))


  1、 首先S以边集M初始化,得到所有的直接连通代价;
  2、 依次考虑第k个结点,对于S中的每一个S[i][j],判断是否满足:
  S[i][j]>S[i][k]+S[k][j],如果满足则用S[i][k]+S[k][j]代替S[i][j],此为第k步;
  3、 k循环取遍所有结点,算法结束时,S为最终解。
  这样的求法自然再简单不过了,但要证明其中的正确性,有些难度,为什么不会使结点
重复存在于同一路径?在替换的时候,S[i][k]S[k][j]中如果同时含有m结点,则这样的替
换显然是错误的,相当于i-->m-->k-->m-->j,可以简单用这有这样连通关系的例子试一下,会
发现如果在一条路径中有结点冗余,则不可能是最短路径,显然上面这条有冗余结点的路径
肯定要比i-->m-->j要长,所以算法在要求最短的同时已经排除了这种情况,这样使得任意一
条路径都不冗余。

 

 

 

Dijikstra算法:

Dijkstra可以处理负权边,不允许有负权环,否则可以通过不断走负权环取得更小值。如果要考虑权值为负的情况可以用Bellman-Ford算法来实现)

大体过程如下:(过程中涉及到一个s集合用来保存已经求出到源点的最短路径的点,一个u集合,保存还没有求出到源点最短路径的点(即全部点的集合A减去集合s所得的集合))

1、  先将源点v加入s集合中;

2、  在剩下的u集合中找到与v有直接关联的边且其权值最小的点,先将该直接边的权值作为该点暂时的最短路径,将s集合里面的各个点与这点关联起来(如果有直接关联的边的话),看从源点v到该点(中间经过若干s集合中的点)的权值之和是不是小于v与该点间直接边的权值,如果小于的话就替换该点的最短路径;

3、  u集合中还有没有点,如果有的话则重复步骤2,否则算法结束

注:在进行上述算法前如果先对各个点之间的权值大小进行排序可以提高算法效率,在步骤2中“在剩下的u集合中找到与v有直接关联的边且其权值最小的点”时可以不用每次都遍历所有的边。

再注:每一次向s中加入一个点之后,对于u集合中的j点的原始最短路径值(与源点有直接关联边的就是直接关联边的权值,没有的话就是无穷大)的影响:如果有影响,那影响后的路径肯定是先经过s集合中的某些点然后再经过刚刚加入s集合的点再直接到j点,而不可能是先经过s集合中的某些点再经过刚刚加入s集合的点,再经过s集合中的其他点(设为x点)再到j点的,因为如果是这样的话那刚刚加入s集合的点(设为k点)应该在x之前就已经加入s集合了的,因为xk之前加入s集合,所以vx的路径长度肯定大于vkx的路径长度,而后面加j的时候都是加上xj的长度,这个显然不合理了的。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值