zoukankan      html  css  js  c++  java
  • 算法之最短路径

    算法之最短路径

    本节内容

    1. 需求提出
    2. 思路分析
    3. 源代码分析

    1.需求提出

    需求:之前写过一个求迷宫路径的算法解决思路,现在需求升级了,光找到路径并不能满足需求,可能该迷宫中含有多条从起点到终点的路径,怎么选择一条最优路径,使得从起点到终点的路径最短?

    2.思路分析

    假设迷宫模型如下:

     1 maze= [
     2     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
     3     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
     4     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
     5     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1],
     6     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
     7     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
     8     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
     9     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    10     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    11     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    12     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    13     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    14     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
    15     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    16 ]

    从左上角的第二行第一列进来,到右下角的倒数第二行最后一列的位置出来,1代表的是用围墙堵死的位置,0代表的是可以通过的位置。那么从入口到出口之间可以有多条路径,选择一条最短路径就成了问题。

    为了解决这个问题,可以设定每个可以到达的位置的权值,因为0和1已经被占用了,所以权值从2开始,入口处位置的权值设置为2,然后每往前走一步的位置,权值增加1。这种情况下方向没有之前的8个方向了,只有[N,E,S,W]四个方向,否则权值设置将会导致混乱。。。

    权值设置完以后,迷宫就变成下面这样了:

     1 1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   
     2 2   3   4   5   6   7   8   9   1   33  34  35  36  37  38  39  1   
     3 1   4   5   6   7   8   9   10  1   32  1   36  37  38  39  40  1   
     4 1   5   6   7   8   9   10  11  1   31  1   37  38  39  1   41  1   
     5 1   6   7   8   9   10  11  12  1   30  1   38  39  40  41  42  1   
     6 1   7   8   9   10  11  12  13  1   29  1   39  40  41  42  43  1   
     7 1   8   9   10  11  12  13  14  1   28  1   40  41  42  43  44  1   
     8 1   9   10  11  12  13  14  15  1   27  1   41  42  43  44  45  1   
     9 1   10  11  12  13  14  15  16  1   26  1   42  43  44  45  46  1   
    10 1   11  12  13  14  15  16  17  1   25  1   43  44  45  46  47  1   
    11 1   12  13  14  15  16  17  18  1   24  1   44  45  46  47  48  1   
    12 1   13  14  15  16  17  18  19  1   23  1   45  46  47  48  49  1   
    13 1   14  15  16  17  18  19  20  21  22  1   46  47  48  49  50  51  
    14 1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1

    把整个迷宫能够走的位置都设置好权值之后,从终点位置往回走,只要下一位置的权值比当前位置的权值低(前提是权值不能为1,是1的话就是墙,而且下一位置的权值最少只会比当前位置的权值少1)那么就把下一位置添加到path这个列表中,到最后将走到起点,这时候path列表里面就是存的一个反向的路径了,再将列表反转一下,就是一个最短路径了。

     3.源代码分析

    源代码如下:

     1 #!/usr/bin/env python
     2 # encoding:utf-8
     3 # __author__: huxianglin
     4 # date: 2016-09-06
     5 # blog: http://huxianglin.cnblogs.com/ http://xianglinhu.blog.51cto.com/
     6 
     7 maze= [  # 定义迷宫
     8     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
     9     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
    10     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    11     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1],
    12     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    13     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    14     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    15     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    16     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    17     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    18     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    19     [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
    20     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
    21     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    22 ]
    23 MOVE = [[0, -1, "N"], [1, 0, "E"], [0, 1, "S"], [-1, 0, "W"]]  # 定义的四个方向坐标的移动
    24 
    25 def shortest_path(start_x,start_y,end_x,end_y):
    26     global maze  # 声明maze是使用的globale作用域的变量
    27     maze[start_y][start_x]=2  # 设置起始位置的权值为2
    28     Queue=[]  # 设置一个空队列用来在设置权值的时候存储邻居节点
    29     while True:
    30         for i in range(4):  # 按照[n,e,s,w]四个方向轮询寻找邻居节点
    31             new_start_x,new_start_y=start_x+MOVE[i][0],start_y+MOVE[i][1]  # 找到的邻居节点的坐标
    32             if maze[new_start_y][new_start_x]==0:  # 只有当邻居节点是0的时候才对邻居节点进行赋权值的操作
    33                 maze[new_start_y][new_start_x]=maze[start_y][start_x]+1  # 给邻居节点赋权值在自身权值基础上加1
    34                 if new_start_x==end_x and new_start_y==end_y:  # 假如邻居节点就是出口节点,那么跳出本次循环
    35                     break
    36                 Queue.append([new_start_x,new_start_y])  # 将刚赋值的邻居节点压入到Queue队列中以供之后使用
    37         if new_start_x==end_x and new_start_y==end_y:  # 假如邻居节点就是出口节点,跳出赋值循环
    38             break
    39         if not Queue:  # 假如队列中没有元素了,也退出赋值循环
    40             print("没有路径")
    41             break
    42         start_x,start_y=Queue.pop(0)  # 取出队列中的第一个元素并对其周边的邻居节点进行赋值操作
    43     #经过上面这些步骤之后,迷宫已经被设置完权值了,下面就是怎样在已赋值好权值后的迷宫中找到一条最短路径了。
    44 
    45     path,Count,here=[],maze[end_y][end_x]-2,[end_x,end_y]   
    46     for i in range(Count-1,-1,-1):  # 因为权值是从2开始的,所以我这里把权值赋初始值的时候就在出口节点权值基础上减去2
    47         path.append(here)  # 将该节点添加到path列表中
    48         for j in range(4):  # 按照[n,e,s,w]四个方向轮询寻找邻居节点
    49             if end_x+MOVE[j][0] in range(len(maze[0])) and end_y+MOVE[j][1] in range(len(maze)):  # 判断邻居节点是否越界
    50                 new_end_x,new_end_y=end_x+MOVE[j][0],end_y+MOVE[j][1]  # 没有越界时找到邻居节点的坐标
    51                 if maze[new_end_y][new_end_x]==i+2:  # 假如邻居节点的权值比当前节点坐标小1的话,就说明邻居节点在最优路径上
    52                     end_x,end_y=new_end_x,new_end_y # 将该邻居节点设置成当前节点并终止之前的再寻找邻居节点过程,寻找下个邻居节点
    53                     break
    54         here=[end_x,end_y]  # 将该邻居节点添加到path列表中
    55     path.reverse() # 经过上面的循环后,得到的path列表里面存储的节点是从终点到起点的路径,将该路径反转一下,就能得到一条最优路径
    56     return path
    57 
    58 if __name__ == "__main__":
    59     start_x, start_y = 0, 1  # 设置起始位置坐标
    60     end_x, end_y = 16, 12  # 设置结束位置坐标
    61     path=shortest_path(start_x,start_y,end_x,end_y)  # 调用shortest_path函数寻找最短路径
    62     for i in maze:  # 打印加上权值以后的迷宫
    63         for j in i:
    64             print("%s	"%j,end="")
    65         print()
    66     print(path)  # 打印最短路径
  • 相关阅读:
    MySQL之数据表的插入内容 空与非空(六)
    输出杨辉三角形
    输入三个double型的数据,放入到a,b,c三个变量中去,使用条件结构与交换逻辑将这三个变量中的值从小到大排列。
    软件测试
    过程设计工具
    设计原理
    总体设计
    生活,也让别人生活
    计算器案例
    需求分析
  • 原文地址:https://www.cnblogs.com/huxianglin/p/5848465.html
Copyright © 2011-2022 走看看