Python实现最短路问题常见求解算法1——Label Correcting Algorithm(deque)

原文链接

1. 适用场景

  • 无负环网络
  • 起点与终点间至少存在一条可行路径
  • 可求解单一起点到多点的最短路径

2. 算法说明

应用标号法求解最短路问题时有两种选择,一是采用 label setting 策略,即 label setting algorithm,如经典的 Dijkstra’s algorithm ,或采用label correcting策略,即 label correcting algorithm,如经典的 FIFO label correcting algorithm、Deque label correcting algorithm

二者在最短路问题上都表现出较好的效率,但与 label setting algorithm算法相比,label correcting algorithm 算法更为灵活,易于扩展,且可以检测出含有负环的网络。本文采用python语言实现Deque label correcting algorithm 对不含负环网络的最短路问题进行求解。对于含有负环网络的最短路问题将在后续文章分享。

3. 测试网络

这里以Tempe ASU网络为测试数据集,网络如下图所示,可通过osm2gmns工具包获取。

在这里插入图片描述

4. 代码实现

(1)定义网络数据结构

# define network data struct
class Network():
    def __init__(self):
        self.node_neighbors={}
        self.node_x_coord={}
        self.node_y_coord={}
        self.node_id_list=[]
        self.number_of_nodes=0
        self.link_cost={}
        self.link_list=[]

        self.source_node_id=0
        self.sink_node_id=1

(2)读取网络文件

# read network csv files
def read_network_file(node_file,link_file,network):
    # read node csv file
    with open(node_file) as node_f:
        node_reader=csv.reader(node_f)
        next(node_reader)
        for row in node_reader:
            network.node_id_list.append(int(row[0]))
            network.node_x_coord[int(row[0])] = float(row[1])
            network.node_y_coord[int(row[0])] = float(row[2])
            network.node_neighbors[int(row[0])] = []
    # read link csv file
    with open(link_file) as f:
        link_reader = csv.reader(f)
        next(link_reader)
        for row in link_reader:
            from_node_id = int(row[1])
            to_node_id = int(row[2])
            cost = float(row[3])
            network.node_neighbors[from_node_id].append(to_node_id)
            network.link_list.append([from_node_id, to_node_id])
            network.link_cost[from_node_id, to_node_id] = cost
    network.number_of_nodes = len(network.node_id_list)
    return network

(3)可视化最短路径

def show_shortest_path(net,path_node_id_list):
    for from_node_id,to_node_id in net.link_list:
        x_coords=[net.node_x_coord[from_node_id],net.node_x_coord[to_node_id]]
        y_coords=[net.node_y_coord[from_node_id],net.node_y_coord[to_node_id]]
        plt.plot(x_coords,y_coords,color='black',linewidth=0.5)
    path_x_coord=[]
    path_y_coord=[]
    for node_id in path_node_id_list:
        path_x_coord.append(net.node_x_coord[node_id])
        path_y_coord.append(net.node_y_coord[node_id])
    plt.plot(path_x_coord,path_y_coord,color='b')
    plt.xlabel('x_coord')
    plt.ylabel('y_coord')
    plt.show()

(4)保存最短路径信息

# save the shortest path information to csv file
def save_to_file(network,path_node_id_list,path_cost,node_predecessor=None,node_label_cost=None):
    outfile = open('shortest_path.csv', 'w', newline='', errors='ignore')
    write = csv.writer(outfile)

    write.writerow(['source_node_id', 'sink_node_id', 'total cost', 'path node id list'])
    path = '-'.join([str(i) for i in path_node_id_list])
    line = [network.source_node_id, network.sink_node_id,path_cost,path]
    write.writerow(line)
    # whether save the shortest path information from  the source node to other nodes
    if node_predecessor and node_label_cost:
        try:
            for node_id in network.node_id_list:
                if node_id!=network.source_node_id and node_id!=network.sink_node_id:
                    path_node_id_list = [node_id]
                    pre_node_id = node_predecessor[node_id]
                    path_cost = 0
                    if node_label_cost[node_id]<float('inf'):
                        while pre_node_id != network.source_node_id:
                            path_node_id_list.insert(0, pre_node_id)
                            path_cost += network.link_cost[path_node_id_list[0], path_node_id_list[1]]
                            pre_node_id = node_predecessor[pre_node_id]
                        path_node_id_list.insert(0, network.source_node_id)
                        path_cost += network.link_cost[path_node_id_list[0], path_node_id_list[1]]
                        path = '-'.join([str(i) for i in path_node_id_list])
                        line = [network.source_node_id, node_id, path_cost, path]
                        write.writerow(line)
                    else:
                        line = [network.source_node_id, node_id, 'inf', 'nan']
                        write.writerow(line)
        except Exception as e:
            pass
    outfile.close()

(5)采用label correcting算法的deque实现寻找最短路径

# find the shortest path from source node to sink node using deque label correcting algorithm
def find_shortest_path(network):
    node_predecessor = {}
    node_predecessor[network.source_node_id]=None
    node_label_cost = { node_id:float('inf') for node_id in network.node_id_list}
    node_label_cost[network.source_node_id] = 0
    SEList = deque()
    SEList_all = []
    SEList.append(network.source_node_id)
    SEList_all.append(network.source_node_id)
    while len(SEList)>0:
        current_node_id=SEList[0]
        SEList.popleft()
        current_node_label_cost = node_label_cost[current_node_id]
        for to_node_id in network.node_neighbors[current_node_id]:
            new_label=current_node_label_cost+network.link_cost[current_node_id,to_node_id]
            if new_label<node_label_cost[to_node_id]:
                node_label_cost[to_node_id]=new_label
                node_predecessor[to_node_id]=current_node_id
                if to_node_id in SEList_all:
                    SEList.insert(0,to_node_id)
                else:
                    SEList.append(to_node_id)
                SEList_all.append(to_node_id)

    path_node_id_list = [network.sink_node_id]
    pre_node_id = node_predecessor[network.sink_node_id]
    path_cost = 0
    if node_label_cost[network.sink_node_id]<float('inf'):
        while pre_node_id != network.source_node_id:
            path_node_id_list.insert(0, pre_node_id)
            path_cost += network.link_cost[path_node_id_list[0], path_node_id_list[1]]
            pre_node_id = node_predecessor[pre_node_id]
        path_node_id_list.insert(0, network.source_node_id)
        path_cost += network.link_cost[path_node_id_list[0], path_node_id_list[1]]
        path = '-'.join([str(i) for i in path_node_id_list])
        print("the trave cost from node id=%s to node id=%s is: %s" % (network.source_node_id, network.sink_node_id, path_cost))
        print("the shortest path from node id=%s to node id=%s is: %s" % (network.source_node_id, network.sink_node_id, path))

        show_shortest_path(network, path_node_id_list)
        save_to_file(network, path_node_id_list, path_cost,node_predecessor,node_label_cost)
    else:
        print("there is no feasible path from node id=%s to node id=%s"%(network.source_node_id,network.sink_node_id))

(6)主程序

if __name__=='__main__':
    # init network data struct
    network=Network()
    # setting source node  id and sink node id
    network.source_node_id=4177
    network.sink_node_id=3881
    # read network files
    read_network_file('./node.csv','./link.csv',network)
    # check whether the source node id and sink node id is in the network
    if network.source_node_id not in network.node_id_list:
        print(" %s not found"%network.source_node_id)
        sys.exit(0)
    if network.sink_node_id not in network.node_id_list:
        print(" %s not found"%network.sink_node_id)
        sys.exit(0)
    # find the shortest path
    find_shortest_path(network)

在这里插入图片描述

https://github.com/PariseC/Shortest_Path_Algorithm/tree/master/label_correcting_algorithm
参考
R.K. Ahuja, T.L. Magnanti and J.B. Orlin, Network Flows: Theory, Algorithms, and Applications. Prentice-Hall, 1993. A comprehensive recent survey of the topic.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值