【改进篇】Python实现VRP常见求解算法——自适应大邻域算法(ALNS)

基于python语言,实现经典自适应大邻域算法(ALNS)对车辆路径规划问题(CVRP)进行求解, 优化代码结构,改进Split函数

往期优质资源

CVRP系列
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
MDVRP系列
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
VRPTW系列
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
HVRP系列
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法
MDHFVRPTW系列
遗传算法
蚁群算法
禁忌搜索算法
模拟退火算法
自适应大邻域算法
粒子群算法
量子粒子群算法
差分进化算法

1. 适用场景

  • 求解CVRP
  • 车辆类型单一
  • 车辆容量不小于需求节点最大需求
  • 单一车辆基地

2. 改进效果对比

这里做了简单的参数敏感性分析,比较不同参数组合下两个版本code的最优值与求解时间的差异。具体为:1)设定权重衰减系数为0.1,0.3,0.5 三个不同等级;2)设定退火速率为0.7,0.75,0.8,0.85,0.9,0.95等不同值;3)设定权重更新步长为2,4,6,8,10等不同值,其他参数固定不变:最大迭代次数为10,车辆容量为80。

2.1 实验结果汇总

改进后的split算子是基于图论的,相对比较耗时,再加上ALNS的贪婪算子需要进行多次计算,因此改进后的算法在时间上的增加额外明显。
在这里插入图片描述

2.2 目标函数对比

rho = 0.1:

在这里插入图片描述

rho = 0.3:

在这里插入图片描述

rho = 0.5:

在这里插入图片描述

2.3 求解时间对比

rho = 0.1:

在这里插入图片描述

rho = 0.3:

在这里插入图片描述

rho = 0.5:

在这里插入图片描述

3. 求解结果

(1)收敛曲线

在这里插入图片描述

(2)车辆路径

在这里插入图片描述

(3)输出文件

在这里插入图片描述

4. 部分代码

(1)数据结构

# 数据结构:解
class Sol():
    def __init__(self):
        self.node_no_seq=None # 解的编码
        self.obj=None # 目标函数
        self.action_id=None # 算子id
        self.route_list=None # 解的解码
        self.route_distance = None  # 车辆路径的长度集合
# 数据结构:网络节点
class Demand():
    def __init__(self):
        self.id = 0 # 节点id
        self.x_coord = 0 # 节点平面横坐标
        self.y_coord = 0  # 节点平面纵坐标
        self.demand = 0 # 节点需求
# 数据结构:全局参数
class Model():
    def __init__(self):
        self.best_sol = None # 全局最优解
        self.demand_dict = {}  # 需求节点集合
        self.demand_id_list = []
        self.sol_list = []  # 解的集合
        self.depot = None # 车场节点
        self.number_of_nodes = 0 # 需求节点数量
        self.vehicle_cap = 80 # 车辆最大容量
        self.distance_matrix = {}
        self.popsize = 100 # 种群规模
        self.alpha = 2 # 信息启发式因子
        self.beta = 3 # 期望启发式因子
        self.Q = 100 # 信息素总量
        self.rho = 0.5 # 信息素挥发因子
        self.tau = {} # 弧信息素集合
        self.vehicle_cap=0  # 车辆最大容量

(2)距离矩阵

def calDistanceMatrix(model):
    for i in range(len(model.demand_id_list)):
        f_n = model.demand_id_list[i]
        for j in range(i + 1, len(model.demand_id_list)):
            t_n = model.demand_id_list[j]
            dist = math.sqrt((model.demand_dict[f_n].x_coord - model.demand_dict[t_n].x_coord) ** 2
                             + (model.demand_dict[f_n].y_coord - model.demand_dict[t_n].y_coord) ** 2)
            model.distance_matrix[f_n, t_n] = dist
            model.distance_matrix[t_n, f_n] = dist
            model.tau[f_n, t_n] = 100
            model.tau[t_n, f_n] = 100

        dist = math.sqrt((model.demand_dict[f_n].x_coord - model.depot.x_coord) ** 2
                         + (model.demand_dict[f_n].y_coord - model.depot.y_coord) ** 2)
        model.distance_matrix[f_n, model.depot.id] = dist
        model.distance_matrix[model.depot.id, f_n] = dist

(3)路径提取

def extractRoutes(node_no_seq,P,depot_id):
    route_list = []
    route = []
    p = P[node_no_seq[0]]
    for node_seq in node_no_seq:
        if P[node_seq] == p:
            route.append(node_seq)
        else:
            route.insert(0,depot_id)
            route.append(depot_id)
            route_list.append(route)
            route = [node_seq]
            p = P[node_seq]
    return route_list

(4)破坏算子

# 随机破坏
def createRandomDestory(model):
    d=random.uniform(model.rand_d_min,model.rand_d_max)
    return random.sample(model.node_id_list,int(d*(len(model.node_id_list)-1)))
# 最坏值破坏
def createWorseDestory(model,sol):
    deta_f=[]
    for node_no in sol.node_no_seq:
        node_no_seq_=copy.deepcopy(sol.node_no_seq)
        node_no_seq_.remove(node_no)
        obj,_,_=calObj(node_no_seq_,model)
        deta_f.append(sol.obj-obj)
    sorted_id = sorted(range(len(deta_f)), key=lambda k: deta_f[k], reverse=True)
    d=random.randint(model.worst_d_min,model.worst_d_max)
    return [sol.node_no_seq[i] for i in sorted_id[:d]]

(5)收敛曲线

# 绘制目标函数收敛曲线
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()

(6)车辆路径

# 绘制优化车辆路径
def plotRoutes(model):
    for route in model.best_sol.route_list:
        x_coord=[]
        y_coord=[]
        for node_no in route:
            x_coord.append(model.demand_dict[node_no].x_coord)
            y_coord.append(model.demand_dict[node_no].y_coord)
        plt.plot(x_coord,y_coord,marker='s',color='b',linewidth=0.5)
    plt.show()

(7)输出结果

# 输出结果
def outPut(model):
    work=xlsxwriter.Workbook('result.xlsx')
    worksheet=work.add_worksheet()
    worksheet.write(0, 0, 'id')
    worksheet.write(0, 1, 'route')
    worksheet.write(0, 2, 'distance')
    worksheet.write(0, 3, 'total_distance')
    worksheet.write(1,3,model.best_sol.obj)
    for id,route in enumerate(model.best_sol.route_list):
        r=[str(i)for i in route]
        worksheet.write(id + 1, 0, f'v{str(id + 1)}')
        worksheet.write(id + 1, 1, '-'.join(r))
        worksheet.write(id + 1, 2, model.best_sol.route_distance[id])
    work.close()

5. 完整代码

如有错误,欢迎交流。

私信,有偿

参考

  1. A simple and effective evolutionary algorithm for the vehicle routing problem
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Better.C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值