Java教程

迪杰斯特拉算法-西安地铁最短路线问题

本文主要是介绍迪杰斯特拉算法-西安地铁最短路线问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章说明

       图是一种较线性表和树更为复杂的数据结构,在各个领域都有着广泛的应用,如城市交通、电路网络分析、交通灯的设置等,其中,最短路径问题的求解是日常生活中最为常见的问题。在现实生活和生产实践中,有许多管理、组织与计划中的优化问题,如在企业管理中,如何定制管理计划和设备购置计划,使得收益最大或费用最小。这类问题可以借助图论知识得以很好的解决。在本文中,我们会讨论图论的最短路径问题,紧接着介绍最短路径问题中的经典算法-迪杰斯特拉算法。最后,我们会将迪杰斯特拉算法运用到实践中,结合西安的地铁路线,目的是求解从一个站点到另一个站点的最短路径,在这里,我们的路径不是现实中的道路长度,而是从一个站点到另一个站点所用的时间。我们还会给出具体的算法程序以及执行结果。

      这篇文章是图论众多算法中的一个简单应用,适用于与之相关的图论作业,如老师让将图论算法于实际例子结合等。而该文章是将迪杰斯特拉算法与现实中的实例,也就是与西安地铁路线结合,用以选择从地铁中地点A到地点B的最短路径,有一定的实际意义。

1、最短路径问题

       在现实世界中,我们会面临路径选择问题,例如,从家到学校的路有n条,你要从这n条路线中选择一条具有最小代价的路线,结合到现实中选择一条具有最小代价的路线就是找到一条路程最短或者花费时间最少的一条路径,我们可以统称之为最短路径问题。下面我们给出具体的描述。

定义1. 设H为带权图G=<V,E,W>的一个子图,H的每条边的权的和称为H的权。若H是一条路p,则称其权为路p的长。

      在带权图中给定了结点u以及结点。若u,v连通,则uv可能有若干条路,这些路中一定有一条长度最小的路,这样的路称之为uv的最短路。最短路的长也称uv的距离,记为d(u,v)。求给定两个结点之间的最短路问题称为最短路问题。要注意的是,这里所说的长具有广泛的意义,既可指普通意义的距离,也可以是时间或费用等,我们下文中所用到的距离是指时间,从A站到B站所用到的时间(单位为分钟)为我们图的距离。

2、迪杰斯特拉算法

Dijkstra算法是由荷兰计算机科学家狄克斯特拉于1959年提出来的,因此又叫狄克斯特拉算法。它是从一个结点到其余各结点的最短路径算法。狄克斯特拉于1972年获得美国计算机协会授予的图灵奖,这是计算机科学中最具有声望的奖项之一。

2.1 迪杰斯特拉算法基本思想

       把图中所有结点分为两组,每一个结点对应一个距离值。第一组包括已确定最短路径的结点,结点对应的距离值是由v_{0}到此结点的最短路径长度。第二组包括尚未确定最短路径的结点,结点对应的距离值是v_{0}到此结点(中间结点)至此结点的最短路径长度。

      按最短路径长度递增的顺序把第二组的结点加到第一组中去,直至v_{0}可达的所有结点都包含于第一组。在这个过程中,总保持从v_{0}到第一组各结点的最短路径长度都不大于从v_{0}至第二组任何结点的路径长度。

      设源点为v_{0},初始时v_{0}进入第一组,v_{0}的距离值为0;第二组包含其他所有结点,这些结点对应的距离值定义为(设v_{i}为第二组中的结点)

                                               d_{0i}=\left\{\begin{matrix} W_{0i},(v_{0}\in E)\\ \infty ,(v_{0},v_{i}\notin E) \end{matrix}\right.

然后每次从第二组的结点中选一个其距离值为最下的结点v_{m}加入到第一组中。每往第一组中加入一个结点v_{m},就要对第二组的各结点的距离值做一次修改(设v_{i}是第二组的结点)。

       若加进中间结点v_{m}使得v_{0}v_{i}的路径长度更短(即d_{0i}>d_{0m}+w_{mi}),则要修改v_{i}的距离(d_{0i}\leftarrow d_{0m}+w_{mi})。修改后再选距离值最小的一个结点加入到第一组中,......如此进行下去,直至第一组囊括图的所有结点或再无可加入第一组的结点存在。算法的具体描述如下。

算法描述(求加权简单连通图G一个结点到其余各结点的最短路径):

G有结点a=v_{0},v_{1},...,v_{n}=z,权w(v_{i},v_{j})=w_{ij}>0,若e(v_{i},v_{j})不是G的边,则w_{ij}=\infty.

(1) 令l(a)=0,l(v_{i})=\infty,i=1,2,...n,S=\varnothing ;

(2) 若Z\notin S,则令取u不属于Sl(u)最小的结点(若有多个可任选一个),令S=S\cup{u},重复执行(2);

(3) 对于所有不属于S的结点v,若l(u)+w(u,v)<l(u),则令l(v)=l(u)+w(u,v);

(4)l(z)即为az的最短路径。

以上便是算法的描述,这是本文问题的算法的核心内容。

3 西安地铁问题

                                          图3.1 西安地铁路线(部分)

      上图是西安到目前为止所开通的地铁路线,总共有五条路线,分别为1号线、2号线、3号线、4号线以及机场城际线,不同的路线用不同的颜色表示。之所以选择西安地铁,主要是因为针对问题的数据没找到,所以就选择了一个地铁数相对较少的城市,这样比较方便统计数据,方便后面的工作进行。还有就是我在西安读了大学,特别喜欢这座城市。其他城市的地铁路线虽然比较多,但总的来说是求解最短路径方法是和西安地铁一样的,所以解决了西安地铁的问题之后其他的也不是问题。

3.1 数据处理

      地图上面各个地铁站点就相当于图中的结点,所以我这次就以站点来表示图的结点,例如有站点a和站点b。同理,若地图上两个结点间有相连的边,也就是现实中这两个结点一站可达,那么图中这两个结点a和b间就有边,边的权为列车从a站点到b站点的所用的时间,单位为分钟。

                                                           图3.2 去除掉的数据实例

      我还去除了部分站点的数据,如上图中,地铁一号线的一端,我们去掉了从玉祥门到终点站上林路之间的所有站点,因为任何站点(不包括我们去除掉的点)到我们一号线上去掉的点的洒金桥那一端,可以先求从其他点到洒金桥的路程,然后再求从洒金桥到到该结点的距离,加起来即可。反之亦可。

       我还抽象后增加了部分结点,例如上图中的北大街,为地铁一号线和地铁二号线的交点,我将该结点分为北大街1以及北大街2,分别代指地铁一号线上的北大街以及地铁二号线上的北大街。其中,北大街1到北大街2之间有边,边的权值为我们得推测值,这在现实中为我们转站所花费的时间,我给的估计值为3分钟。

       数据来源于高德地图上面的信息,选取了各个站点的列车发车时刻表,站点a和站点b相连,也就是它们之前有边,站点a与站点b之间的边的权值为两站点列车发车时间表之间的差值的绝对值。我们总共记录了48个结点以及它们之间边的权值,用以后续的工作。具体的数据见附录1。

3.2 算法的实现

      算法的实现非常简单,这次图论实践,难的地方是找方向和数据以及数据的处理过程。首先,我将上一小节中处理的数据用矩阵的形式存储在xls文件中,这样就方便后面算法具体程序中数据的读写。下面,我将介绍具体算法实现过程

1、读取存储有西安地铁数据的xls文件,并将其转换成numpy矩阵。

2、将numpy矩阵中为0的值设置为9999,意味着路径不可达。

3、将给定的要求的节点加入到已经确定的集合中,并将其标志设置为1,意思是该节点已经确定下来,后续的过程不用再处理该节点。接下来更新其他节点到目标节点的路径长度,值为目标节点到其他节点的度。最后,将目标节点的前置结点信息更新为-1。

4、搜索其他节点到目标节点路径长度的最小值节点,将其加入到已经确定的集合中,更新未加入到已经确定的集合中其他的结点的路径长度,若其他节点到新加入节点的长度加上新加入节点到目标节点的长度小于原先节点路径长度,则更新它,并且将其前置结点置为新加入的结点。

5、重复4,直到所有的结点遍历完毕。

3.3 结果

      实验的结果非常理想,根据前面小节编写的python代码程序可以很容易准确求解到结果,经过我的手动核对,结果准确无误。具体的求解结果可以参照给出的附录文件1。该算法的时间复杂度O(n^3)

4、总结

       本次实验,其目的是根据西安地铁路径图来求解其他地铁站到给定地铁站的最小代价长度,也就是花费的最小时间以及具体的这最小时间的具体乘坐路线。该实验在实际生活中也能得到很不错的应用,比如各地图app上的最优路线推荐。实验的过程也是学习的过程,算法程序思想虽然简单,但和实际的问题结合起来也会有许许多多的问题。遇到问题就会去思考解决的方法,从而进步。


                                                             附录

附录1:迪杰斯塔拉结合西安地铁python代码

# -*- coding: utf-8 -*-
"""
Created on Tue Dec  8 15:22:33 2020

@author: 86150
"""
"""
1、先处理数据
2、perN[i]=k前置点的标号
3、flag[i]=1标志i已经加入到路径中
4、matrix[vs][i]结点i到结点vs的权
5、
"""
import numpy as np
import pandas as pd
class prinm(object):
    def __init__(self,datas,f,e):
        self.datas=datas
        self.lenth=len(datas)#数组长度
        self.perN=np.zeros(self.lenth)#前置结点
        self.f=f
        self.e=e
        self.flag=[0 for i in range(0,self.lenth)]#已经加入到路径中
        self.matrix=[9999 for i in range(0,self.lenth)]#到结点f的权值
    def fit(self):
        #step1:遍历datas f行,然后纪录权值到matrix中
        self.perN[self.f]=-1
        self.flag[self.f]=1
        self.matrix[self.f]=0
        #print(self.flag)
        self.reweight(self.f)
        #选一个权值最小的点
        for i in range(self.lenth-1):
            mi=-1
            value=9998
            for j in range(0,self.lenth):
                if self.matrix[j]<value and self.flag[j]!=1:
                    mi=j
                    value=self.matrix[j]
                #更新
            
            self.flag[mi]=1
            self.reweight(mi)
        return 0
    def reweight(self,v):
        """更新权值"""
        for i in range(0,self.lenth):
            if self.flag[i]!=1:
                if (self.datas[v][i]+self.matrix[v])<self.matrix[i]:
                   self.matrix[i]=(self.datas[v][i]+self.matrix[v])
                   self.perN[i]=v

if __name__ == '__main__':
    fil=pd.read_excel('西安地铁部分数据.xls',sheet_name=[0,1])
    tables=fil[0].values
    tables=np.delete(tables,0,axis=1)
    print(tables.shape)
    tables.astype(int)
    for i in range(0,47):
        for j in range(0,47):
            if tables[i][j]!=0:
                tables[j][i]=tables[i][j]
    for i in range(0,47):
        for j in range(0,47):
            if tables[i][j]==0:
                tables[i][j]=9999
    ta=tables.tolist()
    a=input("请输入a站的数字")
    b=input("请输入b站的数字")
    p=prinm(ta, int(a)-1, int(b)-1)
    p.fit()
    print("a站与b站的最短路径为:"+str(p.matrix[int(b)-1]))
    
                

运行结果:

数据链接:

链接:https://pan.baidu.com/s/1n3bqgZnrddWX_wbDUs4IxQ
提取码:0n6j
--来自百度网盘超级会员V3的分享

    

这篇关于迪杰斯特拉算法-西安地铁最短路线问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!