【进阶二】Python实现VRPTW常见求解算法——自适应大邻域搜索算法(ALNS)

ALNS算法(自适应大领域搜索算法) ALNS的C++实现 阅读详情
AI摘要

本文介绍使用Python实现的自适应大邻域搜索(ALNS)算法解决带时间窗的车辆路径规划问题(VRPTW)。通过具体代码示例展示了如何构造数据结构、读取数据、计算距离时间矩阵、生成初始解、定义破坏与修复算子,并最终通过迭代优化找到最佳路径。

基于python语言,实现经典自适应大邻域搜索算法(ALNS)对带有时间窗的车辆路径规划问题( VRPTW )进行求解。

往期优质资源

1. 适用场景

  • 求解VRPTW
  • 车辆类型单一
  • 车辆容量不小于需求节点最大需求
  • 车辆路径长度或运行时间无限制
  • 需求节点服务成本满足三角不等式
  • 节点时间窗至少满足车辆路径只包含一个需求节点的情况
  • 单个车辆基地
  • 各车场车辆总数满足实际需求

2. 求解效果

(1)收敛曲线在这里插入图片描述

(2)车辆路径
在这里插入图片描述

3. 代码分析

应用ALNS算法求解MDVRPTW时保留了已有代码的架构与思路,为能够求解带有时间窗的(多车场)车辆路径规划问题,这里参考既有文献对路径分割算法进行了改进("splitRoutes"函数),在分割车辆路径时不仅考虑了车辆容量限制,还考虑了节点的时间窗约束,以此使得分割后的路径可行。在此改进下继承了大量原有代码,降低了代码改进量。

4. 数据格式

以csv文件储存数据,其中demand.csv文件记录需求节点数据,共包含需求节点id,需求节点横坐标,需求节点纵坐标,需求量;depot.csv文件记录车场节点数据,共包含车场id,车场横坐标,车场纵坐标,车队数量。需要注意的是:需求节点id应为整数,车场节点id任意,但不可与需求节点id重复。 可参考github主页相关文件。

5. 分步实现

(1)数据结构
定义Sol()类,Node()类,Model()类,其属性如下表:

  • Sol()类,表示一个可行解
属性描述
obj优化目标值
node_id_list需求节点id有序排列集合
cost_of_distance距离成本
cost_of_time时间成本
action_id解所对应的算子id,用于禁用算子
route_list车辆路径集合,对应MDVRPTW的解
timetable_list车辆节点访问时间集合,对应MDVRPTW的解
  • Node()类,表示一个网络节点
属性描述
id物理节点id,需唯一
x_coord物理节点x坐标
y_coord物理节点y坐标
demand物理节点需求
depot_capacity车辆基地车队规模
start_time最早开始服务(被服务)时间
end_time最晚结束服务(被服务)时间
service_time需求节点服务时间
  • Model()类,存储算法参数
属性描述
best_sol全局最优解,值类型为Sol()
demand_dict需求节点集合(字典),值类型为Node()
depot_dict车场节点集合(字典),值类型为Node()
depot_id_list车场节点id集合
demand_id_list需求节点id集合
distance_matrix节点距离矩阵
time_matrix节点旅行时间矩阵
number_of_demands需求节点数量
opt_type优化目标类型,0:最小旅行距离,1:最小时间成本
vehicle_cap车辆容量
vehicle_speed车辆行驶速度,用于计算旅行时间
rand_d_max随机破坏程度上限
rand_d_min随机破坏程度下限
worst_d_max最坏破坏程度上限
worst_d_min最坏破坏程度下限
regret_n次优位置个数
r1算子奖励1
r2算子奖励2
r3算子奖励3
rho算子权重衰减系数
d_weight破坏算子权重
d_select破坏算子被选中次数/每轮
d_score破坏算子被奖励得分/每轮
d_history_select破坏算子历史共计被选中次数
d_history_score破坏算子历史共计被奖励得分
r_weight修复算子权重
r_select修复算子被选中次数/每轮
r_score修复算子被奖励得分/每轮
r_history_select修复算子历史共计被选中次数
r_history_score修复算子历史共计被奖励得分

(2)文件读取

def readCSVFile(demand_file,depot_file,model):
    with open(demand_file,'r') as f:
        demand_reader=csv.DictReader(f)
        for row in demand_reader:
            node = Node()
            node.id = int(row['id'])
            node.x_coord = float(row['x_coord'])
            node.y_coord = float(row['y_coord'])
            node.demand = float(row['demand'])
            node.start_time=float(row['start_time'])
            node.end_time=float(row['end_time'])
            node.service_time=float(row['service_time'])
            model.demand_dict[node.id] = node
            model.demand_id_list.append(node.id)
        model.number_of_demands=len(model.demand_id_list)

    with open(depot_file, 'r') as f:
        depot_reader = csv.DictReader(f)
        for row in depot_reader:
            node = Node()
            node.id = row['id']
            node.x_coord = float(row['x_coord'])
            node.y_coord = float(row['y_coord'])
            node.depot_capacity = float(row['capacity'])
            node.start_time=float(row['start_time'])
            node.end_time=float(row['end_time'])
            model.depot_dict[node.id] = node
            model.depot_id_list.append(node.id)

(3)计算距离&时间矩阵

def calDistanceTimeMatrix(model):
    for i in range(len(model.demand_id_list)):
        from_node_id = model.demand_id_list[i]
        for j in range(i + 1, len(model.demand_id_list)):
            to_node_id = model.demand_id_list[j]
            dist = math.sqrt((model.demand_dict[from_node_id].x_coord - model.demand_dict[to_node_id].x_coord) ** 2
                             + (model.demand_dict[from_node_id].y_coord - model.demand_dict[to_node_id].y_coord) ** 2)
            model.distance_matrix[from_node_id, to_node_id] = dist
            model.distance_matrix[to_node_id, from_node_id] = dist
            model.time_matrix[from_node_id,to_node_id] = math.ceil(dist/model.vehicle_speed)
            model.time_matrix[to_node_id,from_node_id] = math.ceil(dist/model.vehicle_speed)
        for _, depot in model.depot_dict.items():
            dist = math.sqrt((model.demand_dict[from_node_id].x_coord - depot.x_coord) ** 2
                             + (model.demand_dict[from_node_id].y_coord - depot.y_coord) ** 2)
            model.distance_matrix[from_node_id, depot.id] = dist
            model.distance_matrix[depot.id, from_node_id] = dist
            model.time_matrix[from_node_id,depot.id] = math.ceil(dist/model.vehicle_speed)
            model.time_matrix[depot.id,from_node_id] = math.ceil(dist/model.vehicle_speed)

(4)目标值计算
适应度计算依赖" splitRoutes "函数对有序节点序列行解分割得到车辆行驶路线,同时在得到各车辆形式路线后在满足车场车队规模条件下分配最近车场,之后调用 " calTravelCost "函数确定车辆访问各路径节点的到达和离开时间点,并计算旅行距离成本和旅行时间成本。


def calTravelCost(route_list,model):
    timetable_list=[]
    cost_of_distance=0
    cost_of_time=0
    for route in route_list:
        timetable=[]
        for i in range(len(route)):
            if i == 0:
                depot_id=route[i]
                next_node_id=route[i+1]
                travel_time=model.time_matrix[depot_id,next_node_id]
                departure=max(0,model.demand_dict[next_node_id].start_time-travel_time)
                timetable.append((departure,departure))
            elif 1<= i <= len(route)-2:
                last_node_id=route[i-1]
                current_node_id=route[i]
                current_node = model.demand_dict[current_node_id]
                travel_time=model.time_matrix[last_node_id,current_node_id]
                arrival=max(timetable[-1][1]+travel_time,current_node.start_time)
                departure=arrival+current_node.service_time
                timetable.append((arrival,departure))
                cost_of_distance += model.distance_matrix[last_node_id, current_node_id]
                cost_of_time += model.time_matrix[last_node_id, current_node_id]+ current_node.service_time\
                                + max(current_node.start_time - timetable[-1][1] + travel_time, 0)
            else:
                last_node_id = route[i - 1]
                depot_id=route[i]
                travel_time = model.time_matrix[last_node_id,depot_id]
                departure = timetable[-1][1]+travel_time
                timetable.append((departure,departure))
                cost_of_distance +=model.distance_matrix[last_node_id,depot_id]
                cost_of_time+=model.time_matrix[last_node_id,depot_id]
        timetable_list.append(timetable)
    return timetable_list,cost_of_time,cost_of_distance

def calObj(sol,model):

    node_id_list=copy.deepcopy(sol.node_id_list)
    num_vehicle, sol.route_list = splitRoutes(node_id_list, model)
    # travel cost
    sol.timetable_list,sol.cost_of_time,sol.cost_of_distance =calTravelCost(sol.route_list,model)
    if model.opt_type == 0:
        sol.obj=sol.cost_of_distance
    else:
        sol.obj=sol.cost_of_time

(5)初始解

def genInitialSol(node_id_list):
    node_id_list=copy.deepcopy(node_id_list)
    random.seed(0)
    random.shuffle(node_id_list)
    return node_id_list

(6)定义destroy算子(破坏算子)

def createRandomDestory(model):
    d=random.uniform(model.rand_d_min,model.rand_d_max)
    reomve_list=random.sample(range(len(model.demand_id_list)),int(d*len(model.demand_id_list)))
    return reomve_list

def createWorseDestory(model,sol):
    deta_f=[]
    for node_id in sol.node_id_list:
        sol_=copy.deepcopy(sol)
        sol_.node_id_list.remove(node_id)
        calObj(sol_,model)
        deta_f.append(sol.obj-sol_.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)
    remove_list=sorted_id[:d]
    return remove_list

(7)定义repair算子(修复算子)

def createRandomRepair(remove_list,model,sol):
    unassigned_nodes_id=[]
    assigned_nodes_id = []
    # remove node from current solution
    for i in range(len(model.demand_id_list)):
        if i in remove_list:
            unassigned_nodes_id.append(sol.node_id_list[i])
        else:
            assigned_nodes_id.append(sol.node_id_list[i])
    # insert
    for node_id in unassigned_nodes_id:
        index=random.randint(0,len(assigned_nodes_id)-1)
        assigned_nodes_id.insert(index,node_id)
    new_sol=Sol()
    new_sol.node_id_list=copy.deepcopy(assigned_nodes_id)
    calObj(new_sol,model)
    return new_sol

def findGreedyInsert(unassigned_nodes_id,assigned_nodes_id,model):
    best_insert_node_id=None
    best_insert_index = None
    best_insert_cost = float('inf')
    sol_1=Sol()
    sol_1.node_id_list=assigned_nodes_id
    calObj(sol_1,model)
    for node_id in unassigned_nodes_id:
        for i in range(len(assigned_nodes_id)):
            sol_2=Sol()
            sol_2.node_id_list=copy.deepcopy(assigned_nodes_id)
            sol_2.node_id_list.insert(i, node_id)
            calObj(sol_2, model)
            deta_f = sol_2.obj -sol_1.obj
            if deta_f<best_insert_cost:
                best_insert_index=i
                best_insert_node_id=node_id
                best_insert_cost=deta_f
    return best_insert_node_id,best_insert_index

def createGreedyRepair(remove_list,model,sol):
    unassigned_nodes_id = []
    assigned_nodes_id = []
    # remove node from current solution
    for i in range(len(model.demand_id_list)):
        if i in remove_list:
            unassigned_nodes_id.append(sol.node_id_list[i])
        else:
            assigned_nodes_id.append(sol.node_id_list[i])
    #insert
    while len(unassigned_nodes_id)>0:
        insert_node_id,insert_index=findGreedyInsert(unassigned_nodes_id,assigned_nodes_id,model)
        assigned_nodes_id.insert(insert_index,insert_node_id)
        unassigned_nodes_id.remove(insert_node_id)
    new_sol=Sol()
    new_sol.node_id_list=copy.deepcopy(assigned_nodes_id)
    calObj(new_sol,model)
    return new_sol

def findRegretInsert(unassigned_nodes_id,assigned_nodes_id,model):
    opt_insert_node_id = None
    opt_insert_index = None
    opt_insert_cost = -float('inf')
    sol_=Sol()
    for node_id in unassigned_nodes_id:
        n_insert_cost=np.zeros((len(assigned_nodes_id),3))
        for i in range(len(assigned_nodes_id)):
            sol_.node_id_list=copy.deepcopy(assigned_nodes_id)
            sol_.node_id_list.insert(i,node_id)
            calObj(sol_,model)
            n_insert_cost[i,0]=node_id
            n_insert_cost[i,1]=i
            n_insert_cost[i,2]=sol_.obj
        n_insert_cost= n_insert_cost[n_insert_cost[:, 2].argsort()]
        deta_f=0
        for i in range(1,model.regret_n):
            deta_f=deta_f+n_insert_cost[i,2]-n_insert_cost[0,2]
        if deta_f>opt_insert_cost:
            opt_insert_node_id = int(n_insert_cost[0, 0])
            opt_insert_index=int(n_insert_cost[0,1])
            opt_insert_cost=deta_f
    return opt_insert_node_id,opt_insert_index

def createRegretRepair(remove_list,model,sol):
    unassigned_nodes_id = []
    assigned_nodes_id = []
    # remove node from current solution
    for i in range(len(model.demand_id_list)):
        if i in remove_list:
            unassigned_nodes_id.append(sol.node_id_list[i])
        else:
            assigned_nodes_id.append(sol.node_id_list[i])
    # insert
    while len(unassigned_nodes_id)>0:
        insert_node_id,insert_index=findRegretInsert(unassigned_nodes_id,assigned_nodes_id,model)
        assigned_nodes_id.insert(insert_index,insert_node_id)
        unassigned_nodes_id.remove(insert_node_id)
    new_sol = Sol()
    new_sol.node_id_list = copy.deepcopy(assigned_nodes_id)
    calObj(new_sol, model)
    return new_sol

(8)随机选择算子

def selectDestoryRepair(model):
    d_weight=model.d_weight
    d_cumsumprob = (d_weight / sum(d_weight)).cumsum()
    d_cumsumprob -= np.random.rand()
    destory_id= list(d_cumsumprob > 0).index(True)

    r_weight=model.r_weight
    r_cumsumprob = (r_weight / sum(r_weight)).cumsum()
    r_cumsumprob -= np.random.rand()
    repair_id = list(r_cumsumprob > 0).index(True)
    return destory_id,repair_id

(9)执行destory算子

def doDestory(destory_id,model,sol):
    if destory_id==0:
        reomve_list=createRandomDestory(model)
    else:
        reomve_list=createWorseDestory(model,sol)
    return reomve_list

(10)执行repair算子

def doRepair(repair_id,reomve_list,model,sol):
    if repair_id==0:
        new_sol=createRandomRepair(reomve_list,model,sol)
    elif repair_id==1:
        new_sol=createGreedyRepair(reomve_list,model,sol)
    else:
        new_sol=createRegretRepair(reomve_list,model,sol)
    return new_sol

(11)重置算子得分

def resetScore(model):

    model.d_select = np.zeros(2)
    model.d_score = np.zeros(2)

    model.r_select = np.zeros(3)
    model.r_score = np.zeros(3)

(12)更新算子权重

def updateWeight(model):

    for i in range(model.d_weight.shape[0]):
        if model.d_select[i]>0:
            model.d_weight[i]=model.d_weight[i]*(1-model.rho)+model.rho*model.d_score[i]/model.d_select[i]
        else:
            model.d_weight[i] = model.d_weight[i] * (1 - model.rho)
    for i in range(model.r_weight.shape[0]):
        if model.r_select[i]>0:
            model.r_weight[i]=model.r_weight[i]*(1-model.rho)+model.rho*model.r_score[i]/model.r_select[i]
        else:
            model.r_weight[i] = model.r_weight[i] * (1 - model.rho)
    model.d_history_select = model.d_history_select + model.d_select
    model.d_history_score = model.d_history_score + model.d_score
    model.r_history_select = model.r_history_select + model.r_select
    model.r_history_score = model.r_history_score + model.r_score

(13)绘制收敛曲线

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()

(14)绘制车辆路线

def plotRoutes(model):
    for route in model.best_sol.route_list:
        x_coord=[model.depot_dict[route[0]].x_coord]
        y_coord=[model.depot_dict[route[0]].y_coord]
        for node_id in route[1:-1]:
            x_coord.append(model.demand_dict[node_id].x_coord)
            y_coord.append(model.demand_dict[node_id].y_coord)
        x_coord.append(model.depot_dict[route[-1]].x_coord)
        y_coord.append(model.depot_dict[route[-1]].y_coord)
        plt.grid()
        if route[0]=='d1':
            plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5)
        elif route[0]=='d2':
            plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5)
        else:
            plt.plot(x_coord,y_coord,marker='o',color='b',linewidth=0.5,markersize=5)
    plt.xlabel('x_coord')
    plt.ylabel('y_coord')
    plt.show()

(15)输出结果

def outPut(model):
    work=xlsxwriter.Workbook('result.xlsx')
    worksheet=work.add_worksheet()
    worksheet.write(0, 0, 'cost_of_time')
    worksheet.write(0, 1, 'cost_of_distance')
    worksheet.write(0, 2, 'opt_type')
    worksheet.write(0, 3, 'obj')
    worksheet.write(1,0,model.best_sol.cost_of_time)
    worksheet.write(1,1,model.best_sol.cost_of_distance)
    worksheet.write(1,2,model.opt_type)
    worksheet.write(1,3,model.best_sol.obj)
    worksheet.write(2,0,'vehicleID')
    worksheet.write(2,1,'route')
    worksheet.write(2,2,'timetable')
    for row,route in enumerate(model.best_sol.route_list):
        worksheet.write(row+3,0,'v'+str(row+1))
        r=[str(i)for i in route]
        worksheet.write(row+3,1, '-'.join(r))
        r=[str(i)for i in model.best_sol.timetable_list[row]]
        worksheet.write(row+3,2, '-'.join(r))
    work.close()

(16)主函数

def run(demand_file,depot_file,rand_d_max,rand_d_min,worst_d_min,worst_d_max,regret_n,r1,r2,r3,rho,phi,epochs,pu,v_cap,
        v_speed,opt_type):
    """
    :param demand_file: demand file path
    :param depot_file: depot file path
    :param rand_d_max: max degree of random destruction
    :param rand_d_min: min degree of random destruction
    :param worst_d_max: max degree of worst destruction
    :param worst_d_min: min degree of worst destruction
    :param regret_n:  n next cheapest insertions
    :param r1: score if the new solution is the best one found so far.
    :param r2: score if the new solution improves the current solution.
    :param r3: score if the new solution does not improve the current solution, but is accepted.
    :param rho: reaction factor of action weight
    :param phi: the reduction factor of threshold
    :param epochs: Iterations
    :param pu: the frequency of weight adjustment
    :param v_cap: Vehicle capacity
    :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance
    :return:
    """
    model=Model()
    model.rand_d_max=rand_d_max
    model.rand_d_min=rand_d_min
    model.worst_d_min=worst_d_min
    model.worst_d_max=worst_d_max
    model.regret_n=regret_n
    model.r1=r1
    model.r2=r2
    model.r3=r3
    model.rho=rho
    model.vehicle_cap=v_cap
    model.opt_type=opt_type
    model.vehicle_speed=v_speed
    readCSVFile(demand_file,depot_file, model)
    calDistanceTimeMatrix(model)
    history_best_obj = []
    sol = Sol()
    sol.node_id_list = genInitialSol(model.demand_id_list)
    calObj(sol, model)
    model.best_sol = copy.deepcopy(sol)
    history_best_obj.append(sol.obj)
    for ep in range(epochs):
        T=sol.obj*0.2
        resetScore(model)
        for k in range(pu):
            destory_id,repair_id=selectDestoryRepair(model)
            model.d_select[destory_id]+=1
            model.r_select[repair_id]+=1
            reomve_list=doDestory(destory_id,model,sol)
            new_sol=doRepair(repair_id,reomve_list,model,sol)
            if new_sol.obj<sol.obj:
                sol=copy.deepcopy(new_sol)
                if new_sol.obj<model.best_sol.obj:
                    model.best_sol=copy.deepcopy(new_sol)
                    model.d_score[destory_id]+=model.r1
                    model.r_score[repair_id]+=model.r1
                else:
                    model.d_score[destory_id]+=model.r2
                    model.r_score[repair_id]+=model.r2
            elif new_sol.obj-sol.obj<T:
                sol=copy.deepcopy(new_sol)
                model.d_score[destory_id] += model.r3
                model.r_score[repair_id] += model.r3
            T=T*phi
            print("%s/%s:%s/%s, best obj: %s" % (ep,epochs,k,pu, model.best_sol.obj))
            history_best_obj.append(model.best_sol.obj)
        updateWeight(model)

    plotObj(history_best_obj)
    plotRoutes(model)
    outPut(model)
    print("random destory weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.d_weight[0],
                                                                        model.d_history_select[0],
                                                                        model.d_history_score[0]))
    print("worse destory weight is {:.3f}\tselect is {}\tscore is {:.3f} ".format(model.d_weight[1],
                                                                        model.d_history_select[1],
                                                                        model.d_history_score[1]))
    print("random repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[0],
                                                                       model.r_history_select[0],
                                                                       model.r_history_score[0]))
    print("greedy repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[1],
                                                                       model.r_history_select[1],
                                                                       model.r_history_score[1]))
    print("regret repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[2],
                                                                       model.r_history_select[2],
                                                                       model.r_history_score[2]))

6. 完整代码

有偿,私信

自适应大领域搜索算法(ALNS) 详解及python示例 1 前言 TSP问题的求解方法层出不穷,遗传算法、模拟退火、粒子群算法之类的介绍已经比较多了,同时发现关于自适应大领域搜索算法(Adaptive Large Neighborhood Search, ALNS)的介绍比较少,而且示例代码注释不太详细,刚接触的时候学起来有点费劲,就把学习资料和自己理解的过程写一下,造福和我一样的菜鸟吧。 2 什么是自适应大领域搜索 概念理解:干货 | 自适应大邻域搜索(Adaptive Large Neighborhood Search)入门到精通超详细解析-概念篇 优点、步 阅读详情

相关推荐

【运筹优化】自适应大邻域搜索(ALNS)算法实战:从原理到代码实现与性能调优

本文深入解析自适应大邻域搜索(ALNS)算法,从核心原理到代码实现与性能调优。ALNS作为元启发式算法,通过智能化的破坏-重建策略解决组合优化问题,特别适用于车辆路径规划(VRP)等场景。文章详细介绍了破坏算子、修复算子的设计技巧,以及自适应权重更新机制,并提供了Python实现框架和实战案例,帮助开发者掌握这一高效运筹优化工具。

weixin_31364787的博客 272

着实不错的自适应大邻域搜索算法ALNS

着实不错的自适应大邻域搜索算法ALNS

taozibaby的博客 3589

ALNS算法调参实战:如何让Python版VRPTW求解器效率提升50%?

本文详细介绍了如何通过调优ALNS(自适应大邻域搜索算法)参数,显著提升Python版VRPTW(带时间窗的车辆路径问题)求解器的计算效率。文章提供了破坏算子控制参数、奖励分数与权重更新机制的具体设置建议,并分享了不同规模问题的参数配置策略和高级性能优化技巧,帮助开发者实现效率提升50%以上的实战效果。

weixin_42683392的博客 202

自适应大规模邻域算法(ALNS)解决VRPTW问题(JAVA)

本文介绍了一种启发式算法(ALNS)的Java代码,并用该算法求解了VRPTW问题实例(SolomnC101(100)算例)。结果显示算法的运行时间在可接受范围内。

Made-In-China-0711的博客 8660

用Python搞定物流配送难题:手把手教你用ALNS算法求解带时间窗的VRP(附完整代码)

本文详细介绍了如何使用Python中的自适应大邻域搜索算法(ALNS)解决带时间窗的车辆路径问题(VRPTW)。通过破坏-修复双算子机制,ALNS能高效处理物流配送中的时间窗约束、车辆载重限制等复杂条件。文章包含完整代码实现、数据预处理方法、核心算法设计及电商配送案例解析,帮助开发者快速掌握这一物流优化利器。

weixin_28737603的博客 416

ALNS算法调参实战:如何让你的Python版VRPTW求解器性能提升30%

本文深入探讨了如何通过精细调参提升Python版VRPTW求解器的性能,重点解析了自适应大邻域搜索算法(ALNS)的核心参数及其优化策略。通过分阶段调参、动态参数调整和高级技巧,实现性能提升30%,适用于物流优化和算法工程领域。

weixin_42783709的博客 196

【进阶六】Python实现SDVRPTW常见求解算法——自适应大邻域算法(ALNS)

基于python语言,采用经典自适应大邻域算法(ALNS)对 带硬时间窗的需求拆分车辆路径规划问题(SDVRPTW) 进行求解。

Better.C的博客 1718

元启发式算法实战指南:从原理到工业级VRPTW优化

元启发式算法是一类面向NP-Hard组合优化问题的智能搜索范式,核心在于通过可调控的邻域探索、解质量评估与自适应接受机制,在有限时间内逼近高质量可行解。它不依赖目标函数可导性或精确数学建模,天然适配物流路径规划、生产调度、能源管理等含离散变量、多冲突约束与黑盒目标的实际场景。相比传统整数规划求解器,其技术价值体现在可控计算开销、强业务规则嵌入能力及全程可观测的搜索过程。典型应用如带时间窗的车辆路径问题(VRPTW),可通过自适应大邻域搜索(ALNS)框架实现秒级响应与20%以上运营指标提升。本文聚焦工程落地

weixin_34198762的博客 365

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——自适应大邻域算法(ALNS)

基于python语言,采用经典自适应大邻域算法(ALNS)对 需求拆分车辆路径规划问题(SDVRP) 进行求解。

Better.C的博客 1475

世界冠军之路:菜鸟车辆路径规划求解引擎研发历程

阿里妹导读:车辆路径规划问题(Vehicle Routing Problem, VRP)是物流领域最经典的优化问题之一,具有极大的学术研究意义和实际应用价值。菜鸟网络高级...

阿里技术 3289

绿色物流配送优化:从VRPTW模型到ALNS算法的完整实现

车辆路径问题(VRP)是运筹优化领域的经典课题,旨在为车队规划最优行驶路线以最小化成本。其核心原理是在满足客户需求、时间窗、载重等约束条件下,通过数学建模与算法求解,实现资源的高效配置。随着绿色物流理念的普及,该问题的技术价值进一步凸显,通过将碳排放成本等环境因素量化并纳入目标函数,模型能够引导企业兼顾经济与环境效益。在实际应用中,此类技术广泛支撑着城市配送、供应链管理等场景的决策优化。本文聚焦于带时间窗的绿色车辆路径问题(G-VRPTW),详细阐述了其混合整数规划模型构建,并重点介绍了自适应大邻域搜索(A

weixin_33462167的博客 290

[大邻域算法](MD)VRPTW常见求解算法--代码解析

文章代码的解析篇

panbaoran913的博客 2687

ALNS-VRPPD(Python)自适应大邻域搜索解决取送货的VRP问题(Python)

1、完整代码,可直接运行 (如有疑问可私信) 2、擅长领域:路径规划、机器学习、数据爬虫、数据分析处理等 3、该资源有较为详尽的注解,非常方便大家阅读与理解。 ALNS_VRPPD(Python) 自适应大邻域搜索解决取送货的VRP问题(Python)

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

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

Better.C的博客 2717

wincc 服务器授权型号,WinCC V7.5 SP1软件安装及授权方法

上篇教程给大家介绍了TIA Portal V16 安装方法,今天分享一下WinCC V7.5 SP1。目前V7.5 SP1是WinCC最新的版本,发布时间2019年11月13日。先放一个官网对WinCC V7.5 的介绍视频,感兴趣的可以先看一下。1、软件下载官网下载链接:https://support.industry.siemens.com/cs/document/109772879五个文件下...

weixin_39956110的博客 1万+

从0到1搭建StarRocks3.4.1存算一体架构(VM 虚拟机版)

本文详细介绍了如何在VM虚拟机上从零搭建StarRocks 3.4.1存算一体架构。首先阐述了StarRocks作为高性能分布式SQL数据仓库的优势,重点讲解了其存算一体架构的设计原理。随后提供完整的安装指南,包括环境准备(3台CentOS 8虚拟机配置)、网络互通验证、Java环境配置、软件包解压安装等关键步骤。文章特别详细说明了FE和BE节点的配置文件修改(fe.conf和be.conf)以及必要的防火墙端口开放配置。通过图文并茂的方式,帮助开发者和运维人员快速掌握StarRocks集群部署方法,为后续

小 tom的博客 1331

ALNS算法解决VRPTW城市内即时配送Java/Python代码

这篇博客不涉及算法基本框架,只有我的一些理解以及我写的代码。 在今年我研究了三个月的ALNS算法用于解决城市内即时配送问题,完成了两个版本的代码。在查资料阶段发现很多博客没有写清楚一些细节,在研究了2006年算法创始人的论文后,在此进行总结。 代码需要自己研究然后修改,没办法复制粘贴一般效果不理想。 python代码写的很烂,速度慢,不推荐,可参考画图部分、框架部分。 java代码速度快,易于修改,结构清晰,十分推荐,但没有可视化部分。 代码地址:https://github.com/MonsterPPPP

weixin_45957642的博客 2542

[零基础]用docker搭建Hadoop集群

[零基础]用docker搭建Hadoop集群,每一步都有详细的解释!

weixin_56114243的博客 2万+

数学建模国赛C题复盘:VRPTW模型与ALNS算法实战解析

车辆路径问题是运筹优化领域的经典问题,旨在为车队设计访问多个客户点的最优行驶路线,以最小化成本或时间。其核心原理是将现实中的位置、需求、时间窗等约束,抽象为网络模型中的节点、边和限制条件,通过数学规划方法求解。该技术的价值在于能显著提升物流配送、交通调度等场景的资源利用效率与响应速度。在实际应用中,面对大规模复杂约束,常需借助启发式算法进行高效求解。本文以数学建模竞赛为背景,深入剖析了带容量和时间窗的车辆路径问题的建模过程,并详细介绍了如何运用自适应大邻域搜索算法进行求解,通过数据预处理、结果可视化与灵敏度

weixin_33692284的博客 362

【第07例】IPD体系进阶: 6 个技术评审点(TR)

TR技术评审点

产品线负责人 4421

第十届MathorCup高校数学建模挑战赛-B题:养老服务床位需求预测与运营模式研究

当养老床位数增加时存在的商机,提出了相应的养老服务床位的运营商业模式。就业的可能性,建立多目标规划模型,尽可能同时满足三方面的要求。务床位的需求、制定合理的养老服务床位发展规划,是构建和谐社会、幸福社会。问题一的床位需求与市场类型的分类结果,查找关于国内养老院的相关数据,探。求,又能持续发展养老事业,同时还能促进社会就业的养老服务床位运营的商业。养老服务床位数的增加能够带来的就业方面因素的影响,并对这些因素进行一个。你们的模型及其结论为科学依据,对政府管理部门针对养老床位规划提出合理的。

getusushu的博客 1140

硬核对比:VRPTW的CPLEX/OR-Tools/Python三语言求解方案全解析

本文对带时间窗的车辆路径问题(VRPTW)的三种主流求解方案进行了硬核对比。通过25个客户点的实测数据,详细分析了IBM ILOG CPLEX、Google OR-Tools和自研Python算法在求解效率、代码复杂度、成本及适用场景上的核心差异,为物流调度、路径规划等领域的技术选型提供决策参考。

z4a5b6的博客 689

远程声控系统(MATLAB代码见优快云资源)

远程声控系统技术报告 一、题目要求 实现一个远程声音控制系统。首先采集不同的语音指示信号,进行适当压缩;然后通过噪声信道实现远程传输,远端接收后再通过适当计算识别出是何指示,最后送入一个处于未知状态、但能控/能观的控制系统,完成不同的控制动作。 二、问题分解与解决思路 2.1 系统设计 实验中以汉语数字语音1~9作为指令,数字语音“1”代表一号指令,数字语音“2”代表二号指令,依次类推。发送端发出语音“1”,发送端对应的数字语音文件为“1b.wav”,通过信源编码对语音进行压缩编码,然后进行信道编码并进行基

业精于勤,荒于嬉 5735

ALNS求MDHVRPTW问题 python实现

ALNS python实现 VRP MDHVRPTW 自适应大邻域搜索

anthea_luo的博客 1775

10种电阻综合对比——《器件手册--电阻》

可变电阻在电子设备中也有很多用途,如在收音机的音量调节电路中,通过旋转可变电阻的旋钮来改变电路中的电阻值,从而改变通过扬声器的电流,实现音量的调节。根据电阻定律,电阻R = ρ(L/S),其中ρ是导体材料的电阻率,L是导体的长度,S是导体的横截面积。比如,同样材料制成的两根电线,粗的电线电阻比细的电线电阻小,长的电线电阻比短的电线电阻大。电流采样电阻的工作原理基于欧姆定律,即电阻两端的电压与通过电阻的电流成正比,公式为 I = V/R,其中 I是电流,V是电阻两端的电压,R 是电阻值。

XU157303764的博客 3147

Pytorch实现之SRGAN+CBAM的结构设计

在SRGAN的残差连接中加入了CBAM注意力机制,同时设计了四类损失来训练。

LJ1147517021的博客 572
上一篇: 【进阶二】Python实现VRPTW常见求解算法——模拟退火(SA)
下一篇: 【进阶二】Python实现VRPTW常见求解算法——差分进化算法(DE)
Better.C
博客等级 码龄9年 1万+粉丝 72原创
评论 87
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

Better.C

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

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

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

打赏作者

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

抵扣说明:

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

余额充值