编程实现dijkstra算法 严蔚敏_优化| 手把手教你用Python实现Dijkstra算法(附Python代码和可视化)...

前言

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。该算法在运筹学和数据结构图论部分都有介绍,是一种非常有效的求解单源最短路问题的算法

提示:以下是本篇文章正文内容,下面案例为Solomon标准算例

一、最短路模型

详见上期推文:优化|手把手教你用Python调用Gurobi求解最短路问题

二、迪杰斯特拉算法

原理如下,简单地说它的主要特点是以起始点为中心向外层层扩展(类似于广度优先搜索),将节点由T(temporary)不断更新为P(permanent),直到扩展到终点为止,最终通过回溯上一个节点的办法来得到最短路径。废话少说,直接上代码!

5615624dc88f7c8bd1c1411be0223d8f.pngcopyright@baidu

二、python代码实现

代码如下:

案例中选择使用Solomon标准算例的1000个节点。随机设置起点和终点为418,154号node。

# _*_coding:utf-8 _*_
from __future__ import print_function
from __future__ import division, print_function

import re
import math
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import copy
from matplotlib.lines import lineStyles
import time
import networkx as nx

starttime = time.time()

class Data():
    '''
    the format of solomon dataset
    '''

    def __init__(self):
        self.customerNum = 0  # the number of customers
        self.nodeNum = 0  # the sum of customers and depots
        self.vehicleNum = 0
        self.capacity = 0
        self.cor_X = []
        self.cor_Y = []
        self.demand = []
        self.readyTime = []
        self.dueTime = []
        self.serviceTime = []
        self.disMatrix = {}

    def read_data(self, path, customerNum, depotNum):
        '''
        function to read solomom data from .txt files, notice that it must be solomon dataset
        INPUT
            @ data  : class Data
            @ path  : Data path
            @ customerNum  : the number of customer
        OutPut : none
        '''
        self.customerNum = customerNum
        self.nodeNum = customerNum + depotNum
        f = open(path, 'r')
        lines = f.readlines()
        count = 0
        for line in lines:
            count = count + 1
            if (count == 5):
                line = line[:-1].strip()
                str = re.split(r" +", line)
                self.vehicleNum = int(str[0])
                self.capacity = float(str[1])
            elif (count >= 10 and count <= 10 + customerNum):
                line = line[:-1]
                str = re.split(r" +", line)
                self.cor_X.append(float(str[2]))
                self.cor_Y.append(float(str[3]))
                self.demand.append(float(str[4]))
                self.readyTime.append(float(str[5]))
                self.dueTime.append(float(str[6]))
                self.serviceTime.append(float(str[7]))

        # compute the distance matrix
        self.disMatrix = {}
        for i in range(0, self.nodeNum):
            dis_temp = {}
            for j in range(0, self.nodeNum):
                dis_temp[j] = int(math.hypot(self.cor_X[i] - self.cor_X[j], self.cor_Y[i] - self.cor_Y[j]))
            self.disMatrix[i] = dis_temp

    def plot_nodes(self):
        '''
        Description: function to plot
        '''
        Graph = nx.DiGraph()
        nodes_name = [str(x) for x in list(range(self.nodeNum))]
        Graph.add_nodes_from(nodes_name)
        cor_xy = np.array([self.cor_X, self.cor_Y]).T.astype(int)
        pos_location = {nodes_name[i]: x for i, x in enumerate(cor_xy)}
        nodes_color_dict = ['r'] + ['gray'] * (self.nodeNum - 1)

        nx.draw_networkx(Graph, pos_location, node_size=200, node_color=nodes_color_dict, labels=None,font_size =8)
        plt.show()

    def plot_route(self, route, color='k'):
        Graph = nx.DiGraph()
        nodes_name = [route[0]]
        cor_xy = [[self.cor_X[route[0]], self.cor_Y[route[0]]]]
        edge = []
        edges = [[route[0],route[1]]]
        for i in route[1:]:
            nodes_name.append(i)
            cor_xy.append([self.cor_X[i], self.cor_Y[i]])
            edge.append(i)
            if len(edge) == 2:
                edges.append(copy.deepcopy(edge))
                edge.pop(0)

        Graph.add_nodes_from(nodes_name)
        Graph.add_edges_from(edges)

        pos_location = {nodes_name[i]: x for i, x in enumerate(cor_xy)}
        nodes_color_dict = ['r'] + ['gray'] * (len(route)-2)+['r']

        nx.draw_networkx(Graph, pos_location, node_size=180, node_color=nodes_color_dict, edge_color=color, labels=None,font_size =8)
        plt.show()


# function to read data from .txt files
def readData(path, nodeNum):
    nodeNum = nodeNum;
    cor_X = []
    cor_Y = []

    f = open(path, 'r');
    lines = f.readlines();
    count = 0;
    # read the info
    for line in lines:
        count = count + 1;
        if (count >= 10 and count <= 10 + nodeNum):
            line = line[:-1]
            str = re.split(r" +", line)
            cor_X.append(float(str[2]))
            cor_Y.append(float(str[3]))

    # compute the distance matrix
    disMatrix = [([0] * nodeNum) for p in range(nodeNum)];
    for i in range(0, nodeNum):for j in range(0, nodeNum):
            temp = (cor_X[i] - cor_X[j]) ** 2 + (cor_Y[i] - cor_Y[j]) ** 2
            disMatrix[i][j] = (int)(math.sqrt(temp))
            temp = 0

    return disMatrix


def printData(disMatrix):
    print("-------cost matrix-------\n");
    for i in range(len(disMatrix)):for j in range(len(disMatrix)):# print("%d   %d" % (i, j));print("%6.1f" % (disMatrix[i][j]), end=" ");
        #             print(disMatrix[i][j], end = " ");
        print()





def Dijkstra(Graph, org, des):
        Q = list(Graph.nodes())
        for node in Q:
            if (node == org):
                Graph.nodes[node]['min_dis'] = 0
            else:
                Graph.nodes[node]['min_dis'] = np.inf
        current_node = org
        while (len(Q) > 0):
            min_dis = np.inf
            for node in Q:
                if (Graph.nodes[node]['min_dis']                     current_node = node
                    min_dis = Graph.nodes[node]['min_dis']#找最小的距离的点
            if (current_node != None):
                Q.remove(current_node)
            for child in Graph.successors(current_node):
                arc = (current_node, child)
                dis_temp = Graph.nodes[current_node]['min_dis'] + Graph.edges[arc]['length']
                if (dis_temp 'min_dis'
]):
                    Graph.nodes[child][ 'min_dis'] = dis_temp
                    Graph.nodes[child][ 'previous_node'] = current_node
        min_dis = Graph.nodes[des][ 'min_dis']
        current_node =des
        shortest_path = [current_node] while (current_node != org):
                current_node = Graph.nodes[current_node][ 'previous_node']
                shortest_path.insert( 0, current_node) return  shortest_path, min_dis if __name__ ==  "__main__":
    data = Data()
    path1 =  'C:/Users/asus/Desktop/vrp/Solomn标准VRP算例/homberger_1000_customer_instances/R1_10_1.txt'
    data.read_data(path=path1, customerNum= 1000, depotNum= 1)  # change the path
    nodeNum = 1000
    cost = readData(path1, nodeNum)
    Nodes=[]
    Arcs ={} for i in range(nodeNum):
        Nodes.append(i) for j in range(nodeNum): for i in range(nodeNum): if i != j:
               Arcs[i, j] = cost[i][j]
    Graph = nx.DiGraph() for node in Nodes:
        Graph.add_node(node, min_dis= 0, previous_node=None) for key in Arcs.keys():
        Graph.add_edge(key[ 0], key[ 1], length=Arcs[key])
    org =  418
    des =  154
    shortest_path,min_dis=Dijkstra(Graph, org, des)
    print(shortest_path)
    print(min_dis)
    data.plot_route(shortest_path)
    data.plot_nodes()

结果展示

案例中的1000个点,我们选择起点为418,终点为154号。b5a6ba244e7fe82f1f56f53504b5ac28.png最短路如下:3870f539361f7f6d0a4739c765698423.png结果如下df9c19b98fe1d5549b7d7243b46a5abb.png


作者:

王基光,清华大学,清华伯克利深圳学院(硕士在读) 

刘兴禄,清华大学,清华伯克利深圳学院(博士在读)


往期精彩文章:

优化|手把手教你用Python调用Gurobi求解最短路问题

优化| 手把手教你用Java实现单纯形法

优化| 手把手教你用Python调用Gurobi求解VRPTW

优化 | 两阶段启发式算法求解带时间窗车辆路径问题(附Java代码)

Java调用cplex求解运输问题


编辑:

排版 | 徐璐,清华大学,清华-伯克利深圳学院(硕士在读)

审校 | 周鹏翔,清华大学,清华-伯克利深圳学院(博士在读)


感谢阅读!欢迎大家关注我们的公众号“运小筹”以及粉丝群!

因为微信扫码人数限制,现在扫码加主编微信,拉你进群,掌握运筹学前沿知识~

微信群:

4d05ada0670d244561ba2acb80c64167.png

QQ群:

706e925f685ac9440e1358c979cecbe6.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于您没有指定具体的数据结构和图形库,以下是一个使用Python的NetworkX图形库和Matplotlib可实现Dijkstra算法的示例代码: ```python import networkx as nx import matplotlib.pyplot as plt def dijkstra(graph, start): # 初始距离和前驱节点 distance = {} predecessor = {} for node in graph: distance[node] = float('inf') predecessor[node] = None distance[start] = 0 # 用集合表示未访问的节点 unvisited = set(graph) while unvisited: # 找到未访问节点中距离最小的节点 current = None for node in unvisited: if current is None or distance[node] < distance[current]: current = node # 访问该节点 unvisited.remove(current) # 更新相邻节点的距离和前驱节点 for neighbor, weight in graph[current].items(): new_distance = distance[current] + weight if new_distance < distance[neighbor]: distance[neighbor] = new_distance predecessor[neighbor] = current return distance, predecessor # 创建有向图 G = nx.DiGraph() G.add_edges_from([('A', 'B', {'weight': 5}), ('A', 'D', {'weight': 9}), ('A', 'E', {'weight': 2}), ('B', 'C', {'weight': 2}), ('C', 'D', {'weight': 3}), ('D', 'F', {'weight': 2}), ('E', 'F', {'weight': 3}), ('F', 'G', {'weight': 2})]) # 运行Dijkstra算法 distance, predecessor = dijkstra(G, 'A') # 绘制图形 pos = nx.spring_layout(G) nx.draw_networkx_nodes(G, pos) nx.draw_networkx_edges(G, pos) nx.draw_networkx_labels(G, pos) # 绘制最短路径 path = ['G'] while predecessor[path[-1]] is not None: path.append(predecessor[path[-1]]) path.reverse() edge_labels = {} for i in range(len(path)-1): edge_labels[(path[i], path[i+1])] = distance[path[i+1]] - distance[path[i]] nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=8) nx.draw_networkx_edges(G, pos, edgelist=[(path[i], path[i+1]) for i in range(len(path)-1)], edge_color='r', width=2) plt.axis('off') plt.show() ``` 该代码将创建一个有向图,并使用Dijkstra算法计算从节点A到其他节点的最短路径,并将最短路径绘制为红色。输出的图形如下所示: ![dijkstra_visualization](https://user-images.githubusercontent.com/40957287/133925715-6aafb718-07e7-4e12-9c7e-8a6f78c6f4d6.png)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值