floyd算法

前言

建模时候遇到了一个多源路线最短问题,想到了floyd算法,尝试用python记录了下来,也算是python的一个学习过程。(实际上python上手还是挺容易的,python有一个强大的社区,你遇到不懂得问题只需要搜索,然后调用相关API即可)。

算法原理

Dijkstra

我们先回顾一下图论中另外一种算法:Dijkstra算法
在图论中,寻找最短路径除了Dijkstra算法以外,还有Floyd算法也非常经典,Floyd算法主要计算多元最短路径。
在求单元正权值最短路径时,我们会用Dijkstra算法来求解,算法思想也很简单——贪心算法:传送门
,Dijkstra算法的思想很容易接收,但实际上实现是非常麻烦的,而对于多源(n)结点最短路径中,Dijkstra算法也能求解,只需要将Dijkstra封装一下,然后执行n次即可,但是代码量巨大,对我来说实现困难。

Floyd

Floyd算法又称为插点法,是一种利用动态规划(dp)的思想寻找给定的加权图中多源点之间最短路径的算法。>

    for k in range(0,92):
        for i in range(0, 92):
            for j in range(0, 92):
                len=distance[i][k]+distance[k][j]
                distance[i][j]=min(distance[i][j],distance[i][k]+distance[k][j])

如上,Floyd算法就是三层for循环第一层为一次遍历每个结点,二三层:如果ij两点之间的距离<i经过k再到j的距离,那么就修改ij之间的距离。算法简单,但需要理解,简单来说就是对邻接矩阵进行遍历,所以我们在此之前需要提前构建好邻接矩阵(n阶的一个方阵)。
如果你已经有各个结点之间的关系对和各个结点的左边,那么用python构建邻接矩阵相当方便
如下例
我已从excel中获取了各个结点的编号和坐标,以[(编号,x坐标,y坐标)]的形式存放在AllPoint这个list中。共92个结点
接着我又从excel中获取了结点关系对,即两两直接相连结点的编号,以[(A结点编号,B结点编号)]的形式存放在road这个list中。共140条道路。

生成92阶 0方阵

#先生成0矩阵
    relation_matrix = [[0 for i in range(92)] for j in range(92)]
# 转成int
    for i in range(0, 92):
        for j in range(0, 92):
            relation_matrix[i][j] = (int)(relation_matrix[i][j])

生成邻接矩阵

遍历road列表,把直接相连的两个点的距离算出,改写进邻接矩阵

#################   道路关系邻接矩阵矩阵   ##############   92*92
    for i in range(0,len(road)):
        x_index=(int)(road[i][0])
        y_index=(int)(road[i][1])
        relation_matrix[x_index-1][y_index-1]=relation_matrix[y_index-1][x_index-1]=math.sqrt((AllPoint[x_index-1][1]-AllPoint[y_index-1][1])**2+(AllPoint[x_index-1][2]-AllPoint[y_index-1][2])**2)

将邻接矩阵正对角线置为0,其余不能直达的两点置为inf(无穷)

    for i in range(0,92):
        for j in range(0,92):
            if relation_matrix[i][j]==0:
                relation_matrix[i][j]=float("inf")
        relation_matrix[i][i]=0
        # 打印输出邻接矩阵
        print(relation_matrix[i])

由于矩阵比较大,暂截一部分,可以看到邻接矩阵构造完毕,明显看出此为一个对称方阵
在这里插入图片描述
我们对邻接矩阵深拷贝进distance中,distance用来存放最终的各个点之间最短距离

distance=copy.deepcopy(relation_matrix)

准备工作就绪,我们开始执行我们的Floyd算法:

##########################  弗洛伊德算法  ##############
    for k in range(0,92):
        for i in range(0, 92):
            for j in range(0, 92):
                len=distance[i][k]+distance[k][j]
                distance[i][j]=min(distance[i][j],distance[i][k]+distance[k][j])
    for i in range(0,92):
 		距离矩阵输出
        print(distance[i])

输出结果:

可以看到各点之间的距离都已算出
在这里插入图片描述

实际上,这种邻接矩阵的构造并不是很好,邻接矩阵是一个对称方正,这样构造矩阵多占用了一半的内存资源,造成浪费。
在跑程序的时候,如果矩阵长度太大,稍微多两层循环,matlab会报错matrix长度过大,java会栈溢出,python则会出现超时现象。如果你不想花费时间想其他算法(但也大多会出现同样情况),这时候就要对矩阵进行压缩处理。

邻接矩阵压缩存储

让我们再来回看一下邻接矩阵形式。
在这里插入图片描述
很显然,矩阵中的上三角或下三角是多余的。我们这里去掉上三角,保留下三角,并给他转换成一维的形式(如果只是单纯对上三角赋空,还是用二维矩阵的方式存储,开辟空间不变,达不到优化效果)
在这里插入图片描述
我们很容易看出,第i行我们需要去前i个元素,存储到一维数组中。
我们稍微用一下脑子就可得出:
第i行j列的元素(注意:此处的ij是下标索引),转化到一维数组坐标为
i*(i-1)/2+j-1

具体转化代码如下图:

for i in range(matrix) :
	for j in range(matirx):
			matrix_new[i*(i-1)/2+j-1] = matrix[i][j]
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值