求java实现多车辆、多地点配送路径规划问题(VRP)

_zk 2019-02-21 04:54:44
已知起点、X个订单,对应X个坐标点,在每辆车装货数量一致的情况下,在X个订单中以最优(距离最短)分配给N辆汽车,保证每辆汽车的配送路径是完成全部X个订单中的最有路径,最终返回终点(起点即终点)

...全文
1766 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
零度11989 2021-07-07
  • 打赏
  • 举报
回复 1

博主,我的毕设是这个,你这个有源码吗,我像学习一下

qq_45074945 2021-07-26
  • 举报
回复
@零度11989 import time import pandas as pd import math import random import numpy as np import copy import xlsxwriter import matplotlib.pyplot as plt # 一个可行解 class Sol(): def __init__(self): self.nodes_seq=None self.obj=None self.routes=None # 一个网络节点 class Node(): def __init__(self): self.id=0 self.name='' self.seq_no=0 self.x_coord=0 self.y_coord=0 self.demand=0 # 存储算法参数 class Model(): def __init__(self): self.best_sol=None self.node_list=[] self.sol_list=[] self.node_seq_no_list=[] self.depot=None self.number_of_nodes=0 self.opt_type=0 self.vehicle_cap=0 self.distance={} self.popsize=100 self.alpha=2 # 信息素的重要程度 self.beta=3 # 启发因子的相对重要程度 self.Q=100 # 一个蚂蚁一生的信息素总数 self.rho=0.5 # 信息素挥发因子ρ self.tau={} # 网络弧信息素 # 读取文件信息,主要是目标点信息 def readXlsxFile(filepath,model): node_seq_no = -1 df = pd.read_excel(filepath) for i in range(df.shape[0]): node=Node() node.id=node_seq_no node.seq_no=node_seq_no node.x_coord= df['x_coord'][i] node.y_coord= df['y_coord'][i] node.demand=df['demand'][i] if df['demand'][i] == 0: model.depot=node else: model.node_list.append(node) model.node_seq_no_list.append(node_seq_no) try: node.name=df['name'][i] except: pass try: node.id=df['id'][i] except: pass node_seq_no=node_seq_no+1 model.number_of_nodes=len(model.node_list) # 在初始化参数时计算网络弧距离,同时对网络弧上的信息素浓度进行初始化,这里默认为10,也可取其他值。 def initParam(model): for i in range(model.number_of_nodes): for j in range(i+1,model.number_of_nodes): # d=math.sqrt((model.node_list[i].x_coord-model.node_list[j].x_coord)**2+ # (model.node_list[i].y_coord-model.node_list[j].y_coord)**2) # 距离计算替换为曼哈顿距离 d = abs(model.node_list[i].x_coord - model.node_list[j].x_coord) + abs(model.node_list[i].y_coord - model.node_list[j].y_coord) # 设置矩阵中两个城市之间的距离 model.distance[i,j]=d model.distance[j,i]=d # 设置两个城市之间的初始信息素浓度 model.tau[i,j]=10 model.tau[j,i]=10 # 在更新蚂蚁位置时,调用 " searchNextNode "函数,依据网络弧信息素浓度及启发式信息搜索蚂蚁下一个可能访问的节点。 def movePosition(model): sol_list=[] local_sol=Sol() local_sol.obj=float('inf') for k in range(model.popsize): #Random ant position nodes_seq=[int(random.randint(0,model.number_of_nodes-1))] all_nodes_seq=copy.deepcopy(model.node_seq_no_list) # 将基地移除了 all_nodes_seq.remove(nodes_seq[-1]) #Determine the next moving position according to pheromone while len(all_nodes_seq)>0: next_node_no=searchNextNode(model,nodes_seq[-1],all_nodes_seq) nodes_seq.append(next_node_no) all_nodes_seq.remove(next_node_no) sol=Sol() sol.nodes_seq=nodes_seq sol.obj,sol.routes=calObj(nodes_seq,model) sol_list.append(sol) if sol.obj<local_sol.obj: local_sol=copy.deepcopy(sol) model.sol_list=copy.deepcopy(sol_list) if local_sol.obj<model.best_sol.obj: model.best_sol=copy.deepcopy(local_sol) # 已知当前所在点,求到下一个点的概率 def searchNextNode(model,current_node_no,SE_List): # 初始化数组 prob=np.zeros(len(SE_List)) for i,node_no in enumerate(SE_List): # 距离的倒数就是启发因子 eta=1/model.distance[current_node_no,node_no] tau=model.tau[current_node_no,node_no] prob[i]=((eta**model.alpha)*(tau**model.beta)) #计算蚂蚁选择下一个城市的概率 后面的函数就是在求累积和 cumsumprob=(prob/sum(prob)).cumsum() cumsumprob -= np.random.rand() # 怎么选择的下一个节点 # list(cumsumprob > 0).index(True)生成了下一个节点的下标 # 实际上是被循环调用的,所有的经过筛选为正的都被选上了 next_node_no= SE_List[list(cumsumprob > 0).index(True)] return next_node_no # 更新信息素 def upateTau(model): rho=model.rho for k in model.tau.keys(): model.tau[k]=(1-rho)*model.tau[k] #update tau according to sol.nodes_seq(solution of TSP) for sol in model.sol_list: nodes_seq=sol.nodes_seq for i in range(len(nodes_seq)-1): from_node_no=nodes_seq[i] to_node_no=nodes_seq[i+1] model.tau[from_node_no,to_node_no]+=model.Q/sol.obj #update tau according to sol.routes(solution of CVRP) # for sol in model.sol_list: # routes=sol.routes # for route in routes: # for i in range(len(route)-1): # from_node_no=route[i] # to_node_no=route[i+1] # model.tau[from_node_no,to_node_no]+=model.Q/sol.obj def splitRoutes(nodes_seq,model): num_vehicle = 0 vehicle_routes = [] route = [] # 目前使用容量来控制机器人的数量 remained_cap = model.vehicle_cap for node_no in nodes_seq: if remained_cap - model.node_list[node_no].demand >= 0: route.append(node_no) remained_cap = remained_cap - model.node_list[node_no].demand else: vehicle_routes.append(route) route = [node_no] num_vehicle = num_vehicle + 1 remained_cap =model.vehicle_cap - model.node_list[node_no].demand vehicle_routes.append(route) return num_vehicle,vehicle_routes def calDistance(route,model): distance=0 depot=model.depot for i in range(len(route)-1): from_node=model.node_list[route[i]] to_node=model.node_list[route[i+1]] # distance+=math.sqrt((from_node.x_coord-to_node.x_coord)**2+(from_node.y_coord-to_node.y_coord)**2) distance += abs(from_node.x_coord - to_node.x_coord) + abs(from_node.y_coord - to_node.y_coord) first_node=model.node_list[route[0]] last_node=model.node_list[route[-1]] # distance+=math.sqrt((depot.x_coord-first_node.x_coord)**2+(depot.y_coord-first_node.y_coord)**2) # distance+=math.sqrt((depot.x_coord-last_node.x_coord)**2+(depot.y_coord - last_node.y_coord)**2) distance += abs(depot.x_coord - first_node.x_coord) + abs(depot.y_coord - first_node.y_coord) distance += abs(depot.x_coord - last_node.x_coord) + abs(depot.y_coord - last_node.y_coord) return distance def calObj(nodes_seq,model): num_vehicle, vehicle_routes = splitRoutes(nodes_seq, model) if model.opt_type==0: return num_vehicle,vehicle_routes else: distance=0 for route in vehicle_routes: distance+=calDistance(route,model) return distance,vehicle_routes def plotObj(obj_list): plt.rcParams['font.sans-serif'] = ['SimHei'] #show chinese plt.rcParams['axes.unicode_minus'] = False # Show minus sign plt.plot(np.arange(1,len(obj_list)+1),obj_list) plt.xlabel('Iterations') plt.ylabel('Obj Value') plt.grid() plt.xlim(1,len(obj_list)+1) plt.show() # 绘制路径 def plot_tour(model): plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文 plt.rcParams['axes.unicode_minus'] = False # 显示负号 plt.xlim(-10,100) plt.ylim(0,100) plt.xlabel('x坐标') plt.ylabel('y坐标') plt.text(model.depot.x_coord,model.depot.y_coord,'基地位置') plt.plot(model.depot.x_coord,model.depot.y_coord,'o',color='#0085c3') print(model.best_sol) # model.best_sol.routes[0] # model.node_list[model.best_sol.routes[0]] for i in range(len(model.best_sol.routes)): for j in range(len(model.best_sol.routes[i])): # print(model.node_list[model.best_sol.routes[i][j]].x_coord,model.node_list[model.best_sol.routes[i][j]].y_coord) plt.text(model.node_list[model.best_sol.routes[i][j]].x_coord,model.node_list[model.best_sol.routes[i][j]].y_coord,'任务位置'+str(model.node_list[model.best_sol.routes[i][j]].id - 1)) plt.plot(model.node_list[model.best_sol.routes[i][j]].x_coord,model.node_list[model.best_sol.routes[i][j]].y_coord,'o',color='#0085c3') # plt.plot(model.depot.x_coord,model.depot.y_coord,model.node_list[model.best_sol.routes[0][0]].x_coord,model.node_list[model.best_sol.routes[0][0]].y_coord, color='#0085c3') colors = ['red','blue','yellow','black'] for i in range(len(model.best_sol.routes)): # 连接起点和基地 start = (model.node_list[model.best_sol.routes[i][0]].x_coord, model.depot.x_coord) end = (model.node_list[model.best_sol.routes[i][0]].y_coord, model.depot.y_coord) plt.plot(start, end, color=colors[i]) for j in range(len(model.best_sol.routes[i]) - 1): # 绘图注意start(x1,x2) end(y1,y2) start = (model.node_list[model.best_sol.routes[i][j]].x_coord,model.node_list[model.best_sol.routes[i][j + 1]].x_coord) end = (model.node_list[model.best_sol.routes[i][j]].y_coord,model.node_list[model.best_sol.routes[i][j + 1]].y_coord) plt.plot(start,end,color=colors[i]) # 连接终点和基地 start = (model.node_list[model.best_sol.routes[i][len(model.best_sol.routes[i]) - 1]].x_coord,model.depot.x_coord) end = (model.node_list[model.best_sol.routes[i][len(model.best_sol.routes[i]) - 1]].y_coord,model.depot.y_coord) plt.plot(start, end, color=colors[i]) plt.show() def outPut(model): work=xlsxwriter.Workbook('result.xlsx') worksheet=work.add_worksheet() worksheet.write(0,0,'opt_type') worksheet.write(1,0,'obj') if model.opt_type==0: worksheet.write(0,1,'number of vehicles') else: worksheet.write(0, 1, 'drive distance of vehicles') worksheet.write(1,1,model.best_sol.obj) for row,route in enumerate(model.best_sol.routes): worksheet.write(row+2,0,'v'+str(row+1)) r=[str(i)for i in route] worksheet.write(row+2,1, '-'.join(r)) work.close() def run(filepath,Q,alpha,beta,rho,epochs,v_cap,opt_type,popsize): """ :param filepath:Xlsx file path :param Q:Total pheromone :param alpha:Information heuristic factor :param beta:Expected heuristic factor :param rho:Information volatilization factor :param epochs:Iterations :param v_cap:Vehicle capacity :param opt_type:Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance :param popsize:Population size :return: """ model=Model() model.vehicle_cap=v_cap model.opt_type=opt_type model.alpha=alpha model.beta=beta model.Q=Q model.rho=rho model.popsize=popsize sol=Sol() sol.obj=float('inf') model.best_sol=sol history_best_obj = [] readXlsxFile(filepath,model) initParam(model) for ep in range(epochs): movePosition(model) upateTau(model) history_best_obj.append(model.best_sol.obj) print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj)) plotObj(history_best_obj) outPut(model) plot_tour(model) if __name__=='__main__': file='cvrp1.xlsx' start = time.time() # 机器人的容量在运行蚁群算法是进行调节的 run(filepath=file,Q=10,alpha=1,beta=5,rho=0.1,epochs=100,v_cap=80,opt_type=1,popsize=60) end = time.time() print(end - start)
qq_45074945 2021-07-26
  • 举报
回复 1
@零度11989 目标点是我自己定义的,就不写了
September_cat 2019-09-03
  • 打赏
  • 举报
回复
楼主,功能实现出来了吗
炎灾 2019-05-26
  • 打赏
  • 举报
回复
由简单的程序吗
炎灾 2019-05-26
  • 打赏
  • 举报
回复
个人理解: 这里如果有订单才去算路径的话,性能会很差,所以我的理解是路线是先解析出来的,可以用参考oralce中递归的写法去设计一个数据模型,然后解析出大部分路线,然后如果有订单来的时候 再通过开始地点和结束地点检索出你需要的路径(经过的点最少或者经过的路程最短)
游北亮 2019-05-06
  • 打赏
  • 举报
回复
哈哈,类似于公交车,都是先有线路,再有乘客的, 可能要根据订单分布情况,对线路进行训练和优化
哈希塞特 2019-02-27
  • 打赏
  • 举报
回复
引用 1 楼 多春鱼 的回复:
个人理解: 这里如果有订单才去算路径的话,性能会很差,所以我的理解是路线是先解析出来的,可以用参考oralce中递归的写法去设计一个数据模型,然后解析出大部分路线,然后如果有订单来的时候 再通过开始地点和结束地点检索出你需要的路径(经过的点最少或者经过的路程最短)
应该是这么回事,类似倒排索引的思想,好的思想决定好的程序
多春鱼 2019-02-25
  • 打赏
  • 举报
回复
个人理解: 这里如果有订单才去算路径的话,性能会很差,所以我的理解是路线是先解析出来的,可以用参考oralce中递归的写法去设计一个数据模型,然后解析出大部分路线,然后如果有订单来的时候 再通过开始地点和结束地点检索出你需要的路径(经过的点最少或者经过的路程最短)

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧