最优路径算法(python)

最优路径算法(python实现)

从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径

主要的最优(最短)路径算法:

一、深度优先算法;二、广度优先算法;三、Dijstra最短路径;四、floyd最短路径

深度优先算法

图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。

它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

无向无权值网络
无向无权值网络
data = [[0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0x’x’x’x, 0], [1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 1, 0]]

图解

def depth_first_search(data, data_index):   # 有向、无向都可以满足要求
    d1 = [data_index[0]]
    index_now = 0

    for i in range(len(data_index) - 1):  # 只需要再寻找剩余的数值即可
        state = 1
        for j in range(len(data[index_now])):  # 遍历可行路径
            if data[index_now][j] == 1:  # 如果该路径可行,则直接判断
                if data_index[j] not in d1:  # 判断原始输出中是否已有
                    d1.append(data_index[j])# 无,则加入
                    index_now = j
                    state = 0
                    break
        if state:
            for k in d1[-2::-1]:    # 到达叶子后的操作
                index_now = data_index.index(k)
                for j in range(len(data[index_now])):  # 遍历可行路径
                    if data[index_now][j] == 1:  # 如果该路径可行,则直接判断
                        if data_index[j] not in d1:  # 判断原始输出中是否已有
                            d1.append(data_index[j])  # 无,则加入
                            index_now = j
                            break
                if index_now != data_index.index(k):
                    break

        # print(d1)
    return d1

if __name__ == "__main__":
    data = [[0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 1, 0]]
    data_w = [[0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0],
              [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0]]
    data_index = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    # print(data_index.index('F'))
    d1 = depth_first_search(data_w, data_index)
    print(d1)

输入(无向图):

data = [[0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 1, 0]]
输出:

[‘A’, ‘C’, ‘B’, ‘D’, ‘F’, ‘G’, ‘E’]

广度优先算法

广度优先搜索算法(Breadth First Search),又称为"宽度优先搜索"或"横向优先搜索",简称BFS。

它的思想是:从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。
  
换句话说,广度优先搜索遍历图的过程是以v为起点,由近至远,依次访问和v有路径相通且路径长度为1,2…的顶点。
图解

def breadth_first_search(data, data_index):  # 无向图、有向图都可以的
    d1 = [data_index[0]]
    index_now = [0]
    while len(d1) != len(data_index):
        index_mid = []
        for i in index_now:  # i 为当前 父节点
            for j in range(len(data[i])):  # 查询父节点的子节点
                if data[i][j] == 1:
                    if data_index[j] not in d1:
                        d1.append(data_index[j])
                        index_mid.append(j)
        index_now = index_mid
        print(d1)
    return d1


if __name__ == "__main__":
    data = [[0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 1, 0]]
    data_w = [[0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0],
              [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0]]
    data_index = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    # print(data_index.index('F'))
    d1 = breadth_first_search(data_w, data_index)
    # print(d1)

输入(有向图):

data_w = [[0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0]]
输出:

[‘A’, ‘B’, ‘C’, ‘E’, ‘F’, ‘D’, ‘G’]

Dijstra最短路径(迪杰斯特拉算法)

迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

OSPF协议 :Open Shortest Path First开放式最短路径优先,底层是迪杰斯特拉算法,是链路状态路由选择协议,它选择路由的度量标准是带宽,延迟。

图解

def priority_queue(data, d0):  # 自建优先队列格式
    state = 1
    for i in range(len(data)):
        if d0[1] < data[i][1]:
            data.insert(i, d0)
            state = 0
            break
    if state:
        data.append(d0)
    return data


def dijkstra_search(data, data_index, index):
    parent = {}  # 字典映射,更新前级节点
    queue = []  # 优先队列
    queue_out = [[data_index[index], data[index][index], 0]]  # 输出队列

    while len(queue_out) < len(data_index):
        root_node = data_index.index(queue_out[-1][0])  # 当前最优节点
        # print(root_node)
        for i in range(len(data_index)):  # 遍历所有的可能性
            if data[root_node][i] != -1:  # 检查是否可直连,是
                if data_index[i] not in [x[0] for x in queue_out]:
                    queue = priority_queue(queue,
                                           [data_index[i], data[root_node][i] + queue_out[-1][1], queue_out[-1][0]])
        # print(queue)    # 检查优先队列的情况 [['C', 1], ['B', 5]]

        for i in range(len(queue)):  # 0,1
            # print(queue[i][0])
            if queue[i][0] not in [x[0] for x in queue_out]:
                parent[queue[i][0]] = queue[i][-1]
                queue_out.append(queue[i])
                del queue[i]
                break

        # print(queue)
        # print('queue_out',queue_out)
    return queue_out, parent


if __name__ == "__main__":

    data_weight = [[0, 5, 1, -1, -1, -1], [5, 0, 2, 1, -1, -1], [1, 2, 0, 4, 8, -1], [-1, 1, 4, 0, 3, 6],
                   [-1, -1, 8, 3, 0, -1], [-1, -1, -1, 6, -1, -1]]
    data_index = ['A', 'B', 'C', 'D', 'E', 'F']
    # print(data_index.index('F'))
    d1, d2 = dijkstra_search(data_weight, data_index, 3)
    print(d1)
    print(d2)

    target = 'A'
    for i in d1:
        if i[0] == target:
            print('路径最短距离为:', i[1])

    key = target
    d3 = [target]
    while key in d2.keys():
        d3.insert(0, d2[key])
        key = d2[key]
    print('最优路线为:', d3)

输入:

data_weight = [[0, 5, 1, -1, -1, -1], [5, 0, 2, 1, -1, -1], [1, 2, 0, 4, 8, -1], [-1, 1, 4, 0, 3, 6], [-1, -1, 8, 3, 0, -1], [-1, -1, -1, 6, -1, -1]]
data_index = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’]
d1, d2 = dijkstra_search(data_weight, data_index, 0)
输出:

路径最短距离为: 10
最优路线为: [‘A’, ‘C’, ‘B’, ‘D’, ‘F’]

floyd最短路径

算法的特点:

弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。

算法的思路:

通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入两个矩阵,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。矩阵P中的元素b[i][j],表示顶点i到顶点j经过了b[i][j]记录的值所表示的顶点。

假设图G中顶点个数为N,则需要对矩阵D和矩阵P进行N次更新。初始时,矩阵D中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞,矩阵P的值为顶点b[i][j]的j的值。 接下来开始,对矩阵D进行N次更新。第1次更新时,如果”a[i][j]的距离” > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”),则更新a[i][j]为”a[i][0]+a[0][j]”,更新b[i][j]=b[i][0]。 同理,第k次更新时,如果”a[i][j]的距离” > “a[i][k-1]+a[k-1][j]”,则更新a[i][j]为”a[i][k-1]+a[k-1][j]”,b[i][j]=b[i][k-1]。更新N次之后,操作完成!
Floyd-Warshall算法,简称Floyd算法,用于求解任意两点间的最短距离,时间复杂度为O(n^3)。

使用条件&范围
通常可以在任何图中使用,包括有向图、带负权边的图。

Floyd-Warshall 算法用来找出每对点之间的最短距离。它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。

1.注意单独一条边的路径也不一定是最佳路径。
2.从任意一条单边路径开始。所有两点之间的距离是边的权,或者无穷大,如果两点之间没有边相连。
对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
3.不可思议的是,只要按排适当,就能得到结果。

import sys

sys.setrecursionlimit(100000000)


# 弗洛伊德算法
def floyd():
    n = len(graph)
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if graph[i][k] + graph[k][j] < graph[i][j]:
                    graph[i][j] = graph[i][k] + graph[k][j]
                    parents[i][j] = parents[k][j]  # 更新父结点


# 打印路径
def print_path(i, j):
    if i != j:
        print_path(i, parents[i][j])
    print(j, end='-->')


# Data [u, v, cost]
datas = [
    [0, 1, 2],
    [0, 2, 6],
    [0, 3, 4],
    [1, 2, 3],
    [2, 0, 7],
    [2, 3, 1],
    [3, 0, 5],
    [3, 2, 12],
]

n = 4

# 无穷大
inf = 9999999999

# 构图
graph = [[(lambda x: 0 if x[0] == x[1] else inf)([i, j]) for j in range(n)] for i in range(n)]
parents = [[i] * n for i in range(4)]  # 关键地方,i-->j 的父结点初始化都为i
for u, v, c in datas:
    graph[u][v] = c

floyd()

print('Costs:')
for row in graph:
    for e in row:
        print('∞' if e == inf else e, end='\t')
    print()

print('\nPath:')
for i in range(n):
    for j in range(n):
        print('Path({}-->{}): '.format(i, j), end='')
        print_path(i, j)
        print(' cost:', graph[i][j])

# 最终的graph
# graph[i][j]表示i-->j的最短路径
# 0	2	5	4
# 9	0	3	4
# 6	8	0	1
# 5	7	10	0
#
# Path:
# Path(0-->0): 0--> cost: 0
# Path(0-->1): 0-->1--> cost: 2
# Path(0-->2): 0-->1-->2--> cost: 5
# Path(0-->3): 0-->3--> cost: 4
# Path(1-->0): 1-->2-->3-->0--> cost: 9
# Path(1-->1): 1--> cost: 0
# Path(1-->2): 1-->2--> cost: 3
# Path(1-->3): 1-->2-->3--> cost: 4
# Path(2-->0): 2-->3-->0--> cost: 6
# Path(2-->1): 2-->3-->0-->1--> cost: 8
# Path(2-->2): 2--> cost: 0
# Path(2-->3): 2-->3--> cost: 1
# Path(3-->0): 3-->0--> cost: 5
# Path(3-->1): 3-->0-->1--> cost: 7
# Path(3-->2): 3-->0-->1-->2--> cost: 10
# Path(3-->3): 3--> cost: 0

实例:垃圾回收公司成本问题
某城市有一家垃圾回收公司,负责该城市高新区的所有小区垃圾回收,目前
该公司有多辆垃圾营运专用车,每辆车均可收集多种垃圾。高新区内假定共有 N
个小区(小区编号从 0 开始到 N-1),共有 M 条垃圾车允许通行的路线,每条线
路均有相应的平均路程 S 和平均耗时 T。现要求根据给定的输入信息,编写程序
计算距离最短的路线,如果距离最短的路径存在多条,则要求输出时间最少的路
线。
代码:

import sys

sys.setrecursionlimit(100000000)


# 弗洛伊德算法
def floyd():
    n = len(graph)
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if graph[i][k] + graph[k][j] < graph[i][j]:
                    graph[i][j] = graph[i][k] + graph[k][j]
                    T[i][j] = T[i][k] + T[k][j]
                    parents[i][j] = parents[k][j]  # 更新父结点
                if graph[i][k] + graph[k][j] == graph[i][j]:
                	 if T[i][k] + T[k][j] < T[i][j]:
	                    graph[i][j] = graph[i][k] + graph[k][j]
	                    T[i][j] = T[i][k] + T[k][j]
	                    parents[i][j] = parents[k][j]  # 更新父结点


# 打印路径
def print_path(i, j):
    if i != j:
        print_path(i, parents[i][j])
    print(j, end='-->')


n = int(input("n = "))  #n个点
m = int(input("m = "))  #m条边
start = int(input("start = "))  #起始点
end = int(input("end = "))  #目的点
inf = 9999999999  # 无穷大

datas = [[0]*4]*m
for i in range(m):
	datas[i] = input().split(" ")
#print(datas)

# 构图
graph = [[(lambda x: 0 if x[0] == x[1] else inf)([i, j]) for j in range(n)] for i in range(n)]
T = [[(lambda x: 0 if x[0] == x[1] else inf)([i, j]) for j in range(n)] for i in range(n)]   # 耗时
parents = [[i] * n for i in range(n)]  # 关键地方,i-->j 的父结点初始化都为i
for u, v, s,t in datas:
    graph[u][v] = s
    T[u][v] = t

floyd()

S = graph[start][end]

print_path(start,end)
print(S, T[start][end])


# 最终的graph
# graph[i][j]表示i-->j的最短路径
# 0	2	5	4
# 9	0	3	4
# 6	8	0	1
# 5	7	10	0
#

图
参考博客 :
最短路径问题—Floyd算法详解
Floyd 算法最短路径问题精品(超详解)
最短路径—Dijkstra算法和Floyd算法(理解)
最优路径算法合集(附python源码)(原创)

floyd算法(多源最短路径) python实现(主!)

  • 21
    点赞
  • 157
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Python实现蚁群算法与广度优先搜索求解迷宫最优路径问题源码+exe可执行程序(直接运行).zip 【项目介绍】 该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶, 或者实际项目借鉴参考! 当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。如果基础还行,也可在此代码基础上进行修改,以实现其他功能。 蚁群算法&广度优先算法求解迷宫最优路径问题(附带GUI)<br> Install step1.clone该Repository到你的本地路径 step2.解压缩 项目结构: >aco-bfs-for-Maze-GUI `根目录`<br> >>GUI.exe `打包的exe文件`<br> >>readme.md `readme文件`<br> >>src `源代码文件`<br> >>>GUI.py `GUI代码文件`<br> >>>aco.py `蚁群算法代码文件`<br> >>>bfs.py `广度优先算法代码文件`<br> step3.安装项目运行时所需要的外部库 wxpython:GUI图形库<br> [安装教程](https://www.cnblogs.com/icelee1218/p/8127670.html)<br> Usage 使用任意python代码编辑器或IDE打开`src`文件<br> 运行`GUI.py`<br> ![image]( /readme-imgs/blob/master/aco-bfs-for-Maze-GUI/start.png)<br> 选择`迷宫尺寸`<br> 点击`生成迷宫`<br> ![image]( /readme-imgs/blob/master/aco-bfs-for-Maze-GUI/maze.png)<br> 点击`蚁群算法`执行蚁群算法动画,点击`广度优先算法`执行广度优先算法动画<br> Pack 可使用[PyInstaller](http://www.pyinstaller.org/)将该项目打包成exe格式。<br> `PyInstaller`安装: ``` pip install pyinstaller ``` 使用: ``` pyinstaller -F -w GUI.py ``` 在`GUI.py`相同目录下会新增`dist`文件夹,内部放有`GUI.exe`文件

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值