python、lingo、matlab实现迪杰斯特拉(Dijkstra)算法--最短路径问题

引言

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。 基本思想通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。 
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。

目录

引言

问题描述

最短路径问题

算法思想

操作步骤

实现过程

代码实现

python实现如下

matlab实现如下

lingo实现如下


问题描述

最短路径问题

最短路径问题一直是图论研究的热点问题。例如在实际生活中的路径规划、地图导航等领域有重要的应用。关于求解图的最短路径方法也层出不穷,本篇文章将详细讲解图的最短路径算法。最短路径问题的背景问题一般是类似:已知各城市之间距离,请给出从城市A到城市B的最短行车方案 or 各城市距离一致,给出需要最少中转方案。简而言之:固定起始点的情况下,求最短路。

算法思想

采用标号法。可用两种标号:T标号与 P 标号,T标号为试探性标号(tentative label),P 为永久性标号(permanent label),给 v_{i}点一个P表示从v_{s}v_{i}点的最短路权, v_{i}点的标号不再改变。给 v_{i}点一个 T 标号时,示从v_{s}v_{i}点的估计最短路权的上界,是一种临时标号,凡没有得到 P 标号的点都有 T 标号。算法每一步都把某一点的 T标号改为 P 标号,当终点v_{t}得到 P 标号时,全部计算结束。对于有n个顶点的图,最多经 n-1步就可以得到从始点到终点的最短路。

操作步骤

(1)给v_{s}以P 标号,P(v_{s})=0,其余各点均给 T标号, T(v_{i})=+ ∞。

(2)若v_{i}点为刚得到P 标号的点,考虑这样的点 v_{j}:(v_{i}v_{j})属于 E, 且v_{j}为T标号。对v_{j} 的T标号进行如下的更改:
T(v_{j}) = min[T(v_{j}),P(v_{i}) +l_{\, ij}]

(3) 比较所有具有 T标号的点,把最小者改为 P标号,即

P\left ( \bar{v_{i}} \right )=min\left [ T\left ( v_{i} \right ) \right ]

实现过程

(1)首先给v_{1}以P标号,P\left ( v_{i} \right )=+∞,给其余所有点T标号:

 T(v_{i})=+ ∞ \left ( i= 2,..,6 \right )

(2)由于\left ( v_{1},v_{2} \right ),\left ( v_{1},v_{3} \right ),\left ( v_{1},v_{4} \right )边属于E,且v_{2},v_{3},v_{4}为T标号,所以修改这三个点的标号:

T\left ( v_{2} \right )= min[T\left ( v_{2} \right ),P\left ( v_{1} \right )+l_{\, 12}]= min[+\infty,0+10 ]= 10

T\left ( v_{3} \right )= min[T\left ( v_{3} \right ),P\left ( v_{1} \right )+l_{\, 13}]= min[+\infty,0+7 ]= 7

T\left ( v_{4} \right )= min[T\left ( v_{4} \right ),P\left ( v_{1} \right )+l_{\, 14}]= min[+\infty ,0+8]= 8

 (3)比较所有T标号,T\left ( v_{3} \right )最小,所以令P\left ( v_{3} \right )= 4。并记录路径\left ( v_{1},v_{3} \right )

 (4)v_{3}为刚得到P标号的点,考察\left ( v_{3},v_{4} \right ),\left ( v_{3},v_{5} \right ),\left ( v_{3},v_{6} \right )的端点v_{4},v_{5},v_{6}

T\left ( v_{4} \right )= min[T\left ( v_{4} \right ),P\left ( v_{3} \right )+l_{\, 34}]= min[8,7+3 ]= 8

T\left ( v_{5} \right )= min[T\left ( v_{5} \right ),P\left ( v_{3} \right )+l_{\, 35}]= min[+\infty ,7+9 ]= 16

​​​​​​T\left ( v_{6} \right )= min[T\left ( v_{6} \right ),P\left ( v_{3} \right )+l_{\, 36}]= min[+\infty ,7+9 ]= 16

 (5)全部T标号,T\left ( v_{4} \right )最小,所以令P\left ( v_{4} \right )= 8。并记录路径\left ( v_{1},v_{4} \right )

(6) v_{4}为刚得到P标号的点,考察\left ( v_{4},v_{6} \right )的端点v_{6}

T\left ( v_{6} \right )= min[T\left ( v_{6} \right ),P\left ( v_{4} \right )+l_{\, 46}]= min[16,8+5]= 13

 (7)全部T标号,T\left ( v_{2} \right )最小,所以令P\left ( v_{2} \right )=10。并记录路径\left ( v_{1},v_{2} \right )

 

  (8)v_{2}为刚得到P标号的点,考察\left ( v_{2},v_{5} \right )的端点v_{5}

T\left ( v_{5} \right )= min[T\left ( v_{5} \right ),P\left ( v_{2} \right )+l_{\, 25}]= min[16,10+6]= 16

(9)全部T标号,T\left ( v_{6} \right )最小,所以令P\left ( v_{6} \right )=13。并记录路径\left ( v_{4},v_{6} \right )

  (10) v_{6}为刚得到P标号的点,考察\left ( v_{6} ,v_{5}\right ),\left ( v_{6} ,v_{7}\right )的端点v_{5},v_{7}

T\left ( v_{5} \right )= min[T\left ( v_{5} \right ),P\left ( v_{6} \right )+l_{\, 65}]= min[16,13+2]= 15

T\left ( v_{7} \right )= min[T\left ( v_{7} \right ),P\left ( v_{6} \right )+l_{\, 67}]= min[+\infty ,13+30]= 43

  (11)全部T标号,T\left ( v_{5} \right )最小,所以令P\left ( v_{5} \right )=15。并记录路径\left ( v_{6},v_{5} \right )

 (12) v_{5}为刚得到P标号的点,考察\left ( v_{5} ,v_{7}\right )的端点v_{7}

T\left ( v_{7} \right )= min[T\left ( v_{7} \right ),P\left ( v_{5} \right )+l_{\, 57}]= min[43,15+20]= 35

 (13)全部T标号,v_{7}最小,所以令P\left ( v_{7} \right )=35。并记录路径\left ( v_{5},v_{7} \right )

 自此全部点都已标完P标号,由此可知v_{1}v_{7}的最短路径为:v_{1}\rightarrow v_{4}\rightarrow v_{4}\rightarrow v_{6}\rightarrow v_{5}\rightarrow v_{7},路长为P\left ( v_{7} \right )=35,同时得到v_{1}到其余各个点的最短路。

 如果你不能从图像中直接看出最短路,可以标记P如这种形式:P\left (v _{i},val \right ) i= (1,..,7)

这样就可以比较容易从终点开始逆推找到最短路径。

代码实现

python实现如下

class Graph:
    def __init__(self,num):
        self.data_li = [['inf' for i in range(num)] for j in range(num)]    #创建一个记录每个点到其余个点的路径长度的表,开始时全为inf
        self.path = ['inf' for i in range(num)]
        self.mark = []              #用于记录已经标记过的点
        self.distance = ['inf' for i in range(num)]          #记录目前起始点到其余个的最短距离

    def add_edge(self,data):  #记录各点到可到达的其余点的路径长度
        for i in data:
            self.data_li[i[0]][i[1]] = i[2]

    def dijkstra(self,start):
        self.mark.append(start)
        self.distance[start] = 0
        que = []
        que.append(start)
        while que:
            curnode = que.pop(0)
            for i in range(len(self.data_li[curnode])):
                if i not in self.mark:
                    if  self.distance[i] == 'inf':
                        if self.data_li[curnode][i] == 'inf':
                            continue
                        else:
                            self.distance[i] = self.distance[curnode] + self.data_li[curnode][i]
                            self.path[i] = curnode
                            continue
                    if self.data_li[curnode][i] == 'inf':
                        continue
                    else:
                        if self.distance[curnode] + self.data_li[curnode][i] < self.distance[i]:
                            self.distance[i] = self.distance[curnode] + self.data_li[curnode][i]
                            self.path[i] = curnode
            cur_min_val = [self.distance[i] for i in range(len(self.distance)) if i not in self.mark and self.distance[i] != 'inf']
            if cur_min_val:
                cur_min_val = min(cur_min_val)
                for i in range(len(self.distance)):
                    if i not in self.mark:
                        if self.distance[i] == cur_min_val:
                            self.mark.append(i)
                            que.append(i)
        li = []
        li.append(len(self.path))
        a = len(self.path)-1
        while a:
            if self.path[a] == 'inf':
                break
            else:
                li.insert(0,self.path[a])
                a = self.path[a]
        return li
if __name__ == '__main__':
    data = [(0,1,8),(0,2,10),(0,3,15),(1,4,9),(1,5,11),(2,5,8),(2,6,6),(3,6,14),(4,7,8),(5,7,9),(6,7,10)]
    d = Graph(8)
    d.add_edge(data)
    print(d.dijkstra(0))

matlab实现如下

mark = [];                          %用于记录已经标记过的点
distance = ones(1,7);               %记录目前起始点到其余个的最短距离
distance = distance * 100;
position = ones(1:7);                      %记录新标记的点的来自哪个点
position = position * 100;
data_li = xlsread("C:\Users\24453\Desktop\数学建模题\Dijkstra.xlsx",1,'$A$1:$G$7');
start = 1;
path = dijkstra(start,data_li,mark,distance,position);
function path = dijkstra(start,data_li,mark,distance,position)
    mark = [start];
    position = [start];
    distance(start) = 0;
    que = [start];
    while que
       curnode = que(1);
       que = que(1,2:end);
       for i = 1:length(data_li(curnode,:))
           if ismember(i,mark) == 0
              if distance(i) == 100
                 if data_li(curnode,i) == 100 
                    continue
                 else
                     distance(i) = distance(curnode) + data_li(curnode,i);
                     position(i) = curnode
                     continue
                 end
              end
              if data_li(curnode,i) == 100
                  continue
              else
                  if distance(curnode) + data_li(curnode,i) < distance(i)
                     distance(i) = distance(curnode) + data_li(curnode,i);
                     position(i) = curnode
                  end
              end  
           end
        end
        cur_min_val = [];
        for i = 1:length(distance)
            if ismember(i,mark) == 0 & distance(i) ~= 100
                cur_min_val = [cur_min_val,distance(i)];
            end
        end
        if cur_min_val
           cur_min_val = min(cur_min_val); 
           for i = 1:length(distance)
                if ismember(i,mark) == 0
                    if distance(i) == cur_min_val
                       mark = [mark,i];
                       que = [que,i];
                    end
                end
           end
            
        end   
    end
    path = [];
    path = [path,length(position)];
    a = length(position);
    while a
       if position(a) == 1
           break
       else
           path = [position(a),path];
           a = position(a);
       end
    end
    path = [1,path];
end

lingo实现如下

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

!continue!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值