四、最短路径之Bellman-Ford与SPFA

 1.简介

          针对图中的最短路径计算,Dijkstra基本可以解决大部分问题,但是当图中有负权边出现的时候,该算法不再适用。为了解决该问题,提出了Bellman-Ford算法,适用范围是上去了,但是其复杂度为O(mn),其中m为图边数,n为图顶点数。为此,进行了相关的改进,有两种主要改进方案,其中有一个SPFA算法被广泛使用。

2.相关算法与优化

         Bellman_Ford的流程(以计算从源s到图中其它顶点距离为例):

        (i):初始化数组d[n],其中n为图的顶点个数;d[s]=0,其它任意顶点i的d[i]=∞

       (ii):迭代进行松弛操作:循环n-1次:

                  遍历图中的每条边,对于任意边e(u,v),如果有d[u]>d[v]+w(u,v),则d[v]=d[v]+w(u,v)

       (iii):检验负权回路:遍历图中的边,对于任意边e(u,v),如果d[v-1]>d[u-1]+w(u,v) ,则返回失败,否则正常返回

       Bellman_Ford的改进1:步骤2中的n-1此迭代,导致了Bellman_Ford的效率不高,其中一个改进就是如果在其中一此循环中发现,没有发生松弛操作,则推出循环

       Bellman_Ford的改进之SPFA,其思路是,松弛操作只可能产生在d发生变化的节点中,所以可以缩小进行松弛操作的范围,用队列来进行记录要进行松弛操作的节点:

       (i):初始化数组d和队列sc;其中d[s]=0,其他的d元素为∞,sc为一个队列,将s入队

       (ii):如果队列sc不为空,从中取出一个元素,遍历其与邻接点之间的边,如果邻接点发生松弛操作,而且不在队列sc中,则将该节点入队列;如果队列为空,则停止算法

       基本上SPFA的复杂度为O(km),k《n

3.编程实例

      

import networkx as nx
def bellman_ford(i,G=nx.Graph()):
    d=[]
    for node in G.nodes():
        d.append(100)
    d[i-1]=0
    j=1
    while j<G.number_of_nodes():
        relax=True
        for edge in G.edges():
            u=edge[0]
            v=edge[1]
            if d[v-1]>d[u-1]+G.get_edge_data(u,v)['weight']:
                d[v-1]=d[u-1]+G.get_edge_data(u,v)['weight']
                relax=False
        if relax==True:
            break
        j=j+1
    for edge in G.edges():
        u=edge[0]
        v=edge[1]
        if d[v-1]>d[u-1]+G.get_edge_data(u,v)['weight']:
            return None
    return d

def SPFA(i,G=nx.Graph()):
    d=[]
    sc=[]
    for node in G.nodes():
        d.append(100)
    d[i-1]=0
    sc.append(i)
    while sc:
        node1=sc.pop()
        for node in G.nodes():
            if G.has_edge(node1,node) and d[node-1]>d[node1-1]+G.get_edge_data(node1,node)['weight']:
                d[node-1]=d[node1-1]+G.get_edge_data(node1,node)['weight']
                if node not in sc:
                    sc.append(node)
    return d
                
distance=[]
G=nx.Graph()
G.add_weighted_edges_from([(1,2,8),(1,3,16),(1,5,13),(2,3,7),(2,4,17),(2,5,11),(2,6,10),(3,4,5),(4,5,14),(4,6,6)])
if bellman_ford(1,G):
    distance=bellman_ford(1,G)
    print distance
print SPFA(1,G)

输出:

   《四、最短路径之Bellman-Ford与SPFA》   

参考:
http://www.cnblogs.com/AndreMouche/archive/2011/03/29/1998824.html

http://hi.baidu.com/kerrynit/blog/item/d1d90f33eec11dadd1a2d367.html

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/moodytong/article/details/7662403
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞