我们这里只分析第一问
1.图 1 给出 14 个地点, 其中实线代表各地点之间的路线情况。 若目前所有应急物资集中在第 9 个地点,配送车辆的最大载重量为 1000 千克,采取配送车辆(无人机不参与)的配送模式。请结合附件 1, 建立完成一次整体配送的数学模型, 并给出最优方案。
完成一次整体配送所需要的时间是按照配送车辆从出发开始至全部返回到出发地点的时间来计算。
附件1:
邻接矩阵
每个地点的需求量
首先,我们使用多次迪杰斯特拉算法得到了任意两节点之间的最短路径,然在在此基础上做访问顺序规划。我们以下的建模求解思路就是在暴力枚举的基础上做了剪枝优化,只枚举最近的4个结点的路线。当然,我们是有可能漏掉最佳答案的,但是一般情况下,这种可能性很小很小,所以我们是可以得到全局最优解的。
最短距离矩阵
地点配送顺序
具体路线
9 → 8 → 12 → 11 → 1 → 7 → 5 → 2 → 3 → 5 → 6 → 4 → 6 → 10 → 14 → 13 → 9 9 \to 8 \to 12 \to 11 \to 1 \to 7 \to 5 \to 2 \to 3 \to 5 \to 6 \to 4 \to 6 \to 10 \to 14 \to 13 \to 9 9→8→12→11→1→7→5→2→3→5→6→4→6→10→14→13→9
总距离:582km
总耗时:11.64h
from cmath import inf
from operator import truediv
print("--------------------------读取邻接矩阵---------------------------------")
'''
# 读取邻接矩阵
graph = [] # 保存邻接矩阵
with open("data.csv") as f:
con = list(f.readlines())
for line in con:
line = line.split(',')
line[-1] = line[-1][:-1]
graph.append([int(i) if i != '' else inf for i in line])
n = len(graph) # 地点个数
for i in range(n): # 输出邻接矩阵
print(graph[i])
'''
# 如果没有事先处理好本地文件直接用代码写入邻接矩阵也可
graph = [
[inf , inf , inf , inf , 54 , inf , 55 , inf , inf , inf , 26 , inf , inf , inf ],
[inf , inf , 56 , inf , 18 , inf , inf , inf , inf , inf , inf , inf , inf , inf ],
[inf , 56 , inf , inf , 44 , inf , inf , inf , inf , inf , inf , inf , inf , inf ],
[inf , inf , inf , inf , inf , 28 , inf , inf , inf , inf , inf , inf , inf , inf ],
[54 , 18 , 44 , inf , inf , 51 , 34 , 56 , 48 , inf , inf , inf , inf , inf ],
[inf , inf , inf , 28 , 51 , inf , inf , inf , 27 , 42 , inf , inf , inf , inf ],
[55 , inf , inf , inf , 34 , inf , inf , 36 , inf , inf , inf , 38 , inf , inf ],
[inf , inf , inf , inf , 56 , inf , 36 , inf , 29 , inf , inf , 33 , inf , inf ],
[inf , inf , inf , inf , 48 , 27 , inf , 29 , inf , 61 , inf , 29 , 42 , 36 ],
[inf , inf , inf , inf , inf , 42 , inf , inf , 61 , inf , inf , inf , inf , 25 ],
[26 , inf , inf , inf , inf , inf , inf , inf , inf , inf , inf , 24 , inf , inf ],
[inf , inf , inf , inf , inf , inf , 38 , 33 , 29 , inf , 24 , inf , inf , inf ],
[inf , inf , inf , inf , inf , inf , inf , inf , 42 , inf , inf , inf , inf , 47 ],
[inf , inf , inf , inf , inf , inf , inf , inf , 36 , 25 , inf , inf , 47 , inf ]
]
n = len(graph) # 地点个数
print("-------------------------迪杰斯特拉算法----------------------------------")
# 迪杰斯特拉算法
def Dijkstra(s):
vis = [False for i in range(n)]
vis[s] = True
for i in range(n):
u = -1
MIN = inf
for j in range(n):
if not vis[j] and MIN > graph[s][j]:
u = j
MIN = graph[s][j]
if u == -1:
return
vis[u] = True
for j in range(n):
if not vis[j] and graph[u][j] != inf and graph[s][j] > graph[s][u]+graph[u][j]:
graph[s][j] = graph[s][u] + graph[u][j]
for i in range(n): # 多次迪杰斯特拉得到任意两点的最短路径
Dijkstra(i)
for i in range(n):
print(graph[i])
print("-------------------------最短路径----------------------------------")
# 最小路径回路模型
class MinLoop:
'''
该模型的使用前提是已经用算法整理了任意两点的最短路径的临界矩阵。
我们这里使用的是用多次迪杰斯特拉算法得到的邻接矩阵
'''
def __init__(self,gp_min_dis,min_num,begin):
'''
gp_min_dis : List[List[float]] 或者 numpy二维数组 ---> 记录了图的任意两结点最短路径的邻接矩阵
min_num : int ---> 枚举最近的结点路径数目
begin : int ---> 路径的起始结点的下标
'''
self.gp_min_dis = gp_min_dis
self.num = len(gp_min_dis)
self.min_num = min_num
self.begin = begin
self.allPath = [] # 记录当前模型的所有可能路径
self.allDistance = [] # 记录当前模型的所有可能路径的最短路径
self.min_dis_dict = {} # 将任意两点最短路径备份为字典以免修改原始数据
for i in range(self.num):
self.min_dis_dict[i] = gp_min_dis[i]
# 获取当前模型的所有可能路径
def genAllPath(self):
path = [-1 for _ in range(self.num+1)]
path[0] = self.begin
path[-1] = self.begin
self.DFS(0,self.begin,path)
return self.allPath.copy()
# 深度优先路径搜索
def DFS(self,deep,pos,path):
if deep == self.num-1:
self.allPath.append(path.copy())
return
select = self.getSelect(path,pos)
for nextPos in select:
path[deep+1] = nextPos
self.DFS(deep+1,nextPos,path)
path[deep+1] = -1
# 获取结点的未访问的最近几个结点
def getSelect(self,path,pos):
have = []
for _ in range(self.min_num):
min_dis_pos = -1
min_dis = inf
for j in range(self.num):
if j not in path and j not in have:
if min_dis > self.min_dis_dict[pos][j]:
min_dis = self.min_dis_dict[pos][j]
min_dis_pos = j
if min_dis_pos != -1:
have.append(min_dis_pos)
return have
# 计算路径
def getPathDistance(self,path):
now = self.begin
dis_sum = 0
for to in path[1:]:
dis_sum += self.min_dis_dict[now][to]
now = to
return dis_sum
# 获取当前模型下的所有路径值
def getAlldistance(self):
distance_list = []
for path in self.allPath:
distance_list.append(self.getPathDistance(path))
self.allDistance = distance_list
return distance_list
# 获取该模型的最短路径规划及路径值
def getBestPath(self):
bestDis = min(self.allDistance)
for i in range(len(self.allDistance)):
if bestDis == self.allDistance[i]:
return (self.allPath[i].copy(),bestDis)
return
model = MinLoop(graph,3,8) # 选取最近的3个点进行枚举搜索,这个参数影响最终的运行时间
# 运行模型
model.genAllPath()
model.getAlldistance()
path,dis = model.getBestPath()
for i in range(len(path)):
path[i] += 1 # 将下标改为标号
print("当前模型最短路径规划:",path) # [9, 8, 12, 11, 1, 7, 5, 2, 3, 6, 4, 10, 14, 13, 9]
print("当前模型最短路径值:",dis) # 582.0
print("当前模型最短路径值耗时:",dis/50) # 11.64