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

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

此篇博客介绍了如何使用Python实现自适应大邻域搜索(ALNS)算法解决多车场车辆路径规划(MDCVRP)问题,涉及数据结构、代码实现、关键算子如随机破坏与修复,以及收敛曲线和车辆路径可视化。

基于python语言,实现自适应大邻域搜索算法(ALNS)对多车场车辆路径规划问题(MDCVRP)进行求解。

往期优质资源

1. 适用场景

  • 求解MDCVRP 问题
  • 车辆类型单一
  • 车辆容量不小于需求节点最大需求
  • 多车辆基地
  • 各车场车辆总数满足实际需求

2. 求解效果

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

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

3. 代码分析

车俩路径规划问题按照车场数量可分为单一车场路径规划问题和多车场路径规划问题。针对单一车场条件下仅考虑车辆容量限制的路径规划问题前边帖子中已实现ALNS算法求解,本文采用ALNS算法对多车场条件下仅考虑车辆容量限制的路径规划问题进行求解。为了保持代码的延续性以及求解思路的一致性,这里对上述ALNS算法代码进行如下主要修正实现MDCVRP问题的求解。

  • Model数据结构类中采用demand_dict属性存储需求节点集合,depot_dict属性储存车场节点集合,demand_id_list属性储存需求节点id集合,distance_matrix属性储存任意节点间的欧式距离;
  • Node数据结构类中去掉node_seq属性,增加depot_capacity属性记录车场的车队限制
  • splitRoutes函数中分割车辆路径时分配最近车场作为其车辆提供基地(满足车场车队数量限制)

4. 数据格式

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

5. 分步实现

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

  • Sol()类,表示一个可行解
属性描述
node_id_list需求节点id有序排列集合,对应TSP的解
obj优化目标值
routes车辆路径集合,对应MDCVRP的解
  • Node()类,表示一个网络节点
属性描述
id物理节点id
x_coord物理节点x坐标
y_coord物理节点y坐标
demand物理节点需求
depot_capacity车辆基地车队规模
  • Model()类,存储算法参数
属性描述
best_sol全局最优解,值类型为Sol()
demand_dict需求节点集合(字典),值类型为Node()
depot_dict车场节点集合(字典),值类型为Node()
demand_id_list需求节点id集合
distance_matrix节点距离矩阵
opt_type优化目标类型,0:最小车辆数,1:最小行驶距离
vehicle_cap车辆容量
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'])
            model.demand_dict[node.id] = node
            model.demand_id_list.append(node.id)

    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'])
            model.depot_dict[node.id] = node

(3)计算距离矩阵

def calDistance(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
        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

(4)目标函数计算
适应度计算依赖" splitRoutes “函数对TSP可行解分割得到车辆行驶路线和所需车辆数,在得到各车辆行驶路线后调用” selectDepot “函数,在满足车场车队规模条件下分配最近车场,” calDistance "函数计算行驶距离。

def selectDepot(route,depot_dict,model):
    min_in_out_distance=float('inf')
    index=None
    for _,depot in depot_dict.items():
        if depot.depot_capacity>0:
            in_out_distance=model.distance_matrix[depot.id,route[0]]+model.distance_matrix[route[-1],depot.id]
            if in_out_distance<min_in_out_distance:
                index=depot.id
                min_in_out_distance=in_out_distance
    if index is None:
        print("there is no vehicle to dispatch")
    route.insert(0,index)
    route.append(index)
    depot_dict[index].depot_capacity=depot_dict[index].depot_capacity-1
    return route,depot_dict

def splitRoutes(node_id_list,model):
    num_vehicle = 0
    vehicle_routes = []
    route = []
    remained_cap = model.vehicle_cap
    depot_dict=copy.deepcopy(model.depot_dict)
    for node_id in node_id_list:
        if remained_cap - model.demand_dict[node_id].demand >= 0:
            route.append(node_id)
            remained_cap = remained_cap - model.demand_dict[node_id].demand
        else:
            route,depot_dict=selectDepot(route,depot_dict,model)
            vehicle_routes.append(route)
            route = [node_id]
            num_vehicle = num_vehicle + 1
            remained_cap =model.vehicle_cap - model.demand_dict[node_id].demand

    route, depot_dict = selectDepot(route, depot_dict, model)
    vehicle_routes.append(route)

    return num_vehicle,vehicle_routes

def calRouteDistance(route,model):
    distance=0
    for i in range(len(route)-1):
        from_node=route[i]
        to_node=route[i+1]
        distance +=model.distance_matrix[from_node,to_node]
    return distance

def calObj(node_id_list,model):
    num_vehicle, vehicle_routes = splitRoutes(node_id_list, model)
    if model.opt_type==0:
        return num_vehicle,vehicle_routes
    else:
        distance = 0
        for route in vehicle_routes:
            distance += calRouteDistance(route, model)
        return distance,vehicle_routes

(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算子(破坏算子)
这里实现两种destory:

  • random destroy : 随机从当前解中移除一定比例的需求节点
  • worst 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:
        nodes_id_=copy.deepcopy(sol.node_id_list)
        nodes_id_.remove(node_id)
        obj,vehicle_routes=calObj(nodes_id_,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)
    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)
    new_sol.obj,new_sol.routes=calObj(assigned_nodes_id,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')
    assigned_nodes_id_obj,_=calObj(assigned_nodes_id,model)
    for node_id in unassigned_nodes_id:
        for i in range(len(assigned_nodes_id)):
            assigned_nodes_id_ = copy.deepcopy(assigned_nodes_id)
            assigned_nodes_id_.insert(i, node_id)
            obj_, _ = calObj(assigned_nodes_id_, model)
            deta_f = obj_ - assigned_nodes_id_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)
    new_sol.obj,new_sol.routes=calObj(assigned_nodes_id,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')
    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)):
            assigned_nodes_id_=copy.deepcopy(assigned_nodes_id)
            assigned_nodes_id_.insert(i,node_id)
            obj_,_=calObj(assigned_nodes_id_,model)
            n_insert_cost[i,0]=node_id
            n_insert_cost[i,1]=i
            n_insert_cost[i,2]=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)
    new_sol.obj, new_sol.routes = calObj(assigned_nodes_id, 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.routes:
        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,'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()

(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,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
    readCsvFile(demand_file,depot_file, model)
    calDistance(model)
    history_best_obj = []
    sol = Sol()
    sol.node_id_list = genInitialSol(model.demand_id_list)
    sol.obj, sol.routes = calObj(sol.node_id_list, 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. 完整代码

代码和数据文件可获取:

https://download.youkuaiyun.com/download/python_n/37365542

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

相关推荐

自适应大邻域搜索算法

自适应大邻域搜索算法(Adaptive Large Neighborhood Search)是由Ropke与Pisinger在2006年提出的一种启发式方法,其在邻域搜索的基础上增加了的对算子的作用效果的衡量,使算法能够自动选择好的算子对解进行破坏与修复,从而有一定几率得到更好的解。在邻域搜索算法中,有的算法可以只使用一种邻域,如模拟退火算法,因此它仅仅搜索了解空间的一小部分,找到全局最优的概率较小,它的优势之一是可以避免陷入局部最优;而有的算法可以使用多种算子,如变邻域搜索算法,它通过在当前解的多个邻域中

antien_的博客 1万+

10分钟彻底理解自适应大邻域搜索算法

阅读本文大概需要 10分钟。算法介绍自适应大邻域搜索算法(Adaptive Large Neighborhood Search),简称(ALNS),是由Ropke与Pisinger在20...

木川的技术之路 6242

禁忌搜索算法(TABU)解决路线规划问题(CVRP)

文章目录禁忌搜索算法解决路线规划问题问题定义CVRP问题解决算法禁忌搜索算法局部搜索的两种策略局部搜索的缺点禁忌搜索算法的提出禁忌搜索算法流程图禁忌搜索算法伪码算法结果统计结果详细结果结论代码清单读取测试数据初始解禁忌搜索解法 禁忌搜索算法解决路线规划问题 问题定义 车辆路线规划问题是一个经典的组合优化问题,也是旅行商问题的泛化。该问题的定义为: 有给定数量的客户有运输需求; 为从某个固定地点出...

狂奔的蜗牛 1万+

智能优化系列|第一期:自适应大领域搜索算法(ALNS算法)详解与实战案例(附python代码)

​ Adaptive Large Neighborhood Search (ALNS) 算法是一种元启发式算法,用于解决组合优化问题。ALNS 算法结合了离散优化中的邻域搜索和元启发式算法的特点,能够有效地应对各种复杂的优化问题。 ALNS 算法的核心思想自适应大领域搜索的核心思想是:破坏解、修复解、动态调整权重并选择(自适应)。通过设计多组破坏算子和修复算子,扩大解空间搜索范围,对当前解进行改进,表现好的破坏和修复方法相应地得到高分,权重也越高。在每次迭代中,根据以往表现对各个破坏和修复算子进行选择..

扎实耕耘,终有所获 5681

智能优化算法——篇2(邻域搜索大家族)

目录 1.种群算法和邻域算法的区别与联系 2.算法原理总结 2.1 变邻域搜索算法VNS 2.2 自适应大邻域搜索算法ALNS 在篇1中我们提到,算法很多,但是最经典的有8种,分别是:遗传算法、禁忌搜索算法、模拟退火算法、粒子群算法、蚁群算法、以及邻域搜索中的迭代邻域搜索算法、变邻域搜索算法、自适应大规模邻域搜索算法。前面5种篇1中已有表述,本篇对后面3种做下总结。 这些算法有人叫智能算法,有人叫启发式算法,有人叫元启发式算法等等,其实都可以。 1.种群算法和邻域算法的区别与联系 我之所以分

sinat_41348401的博客 8343

【算法】LNS(大邻域算法)和ALNS(自适应大邻域算法)(持更)(未完)

(原文)假设G为所有客户的集合,n为集合里客户的个数。对每个客户i∈G,要求将质量为li​的货从装货点Pi+​运到卸货点Pi−​.V为车辆v的集合;Qv为车辆v的最大容量;O为车库的集合;设P+≡⋃i∈G​Pi+​, 即为所有装货点的集合,P−≡⋃i∈G​Pi−​,即为所有卸货点的集合,设P≡P+⋃P−,即为所有访问点的集合;设N=P⋃O,即运输网络里所有结点的集合。

panbaoran913的博客 4566

ALNS-自适应大邻域搜索算法

是由Ropke与Pisinger在2006年提出的一种启发式方法,其在邻域搜索的基础上增加了对算子的作用效果的衡量,使算法能够自动选择好的算子对解进行破坏与修复,得到一个成本(cost)最低的一个解。由于算法的自动反馈更新权重机制,根据算子的历史表现与使用次数选择下一次迭代使用的算子,通过算子间的相互竞争来生成当前解的邻域结构,而在这种结构中有很大概率能够找到更好的解,同时可以尽可能地避免出现局部最优解的情况。

Lukkkka77的博客 4349

TIFF文件渲染避坑指南:Three.js与Cesium的5个关键差异点

本文深入对比了Three.js与Cesium在渲染TIFF文件时的5个核心差异点,包括坐标系处理、内存管理、着色器系统、性能优化策略和错误处理机制。重点解析了Cesium的全球WGS84坐标系与Three.js局部坐标系对地理空间数据渲染的根本影响,并提供了针对性的性能优化与调试方案,帮助开发者根据项目需求选择合适的3D引擎并有效避坑。

weixin_29243279的博客 334

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

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

Made-In-China-0711的博客 8660

电压抬升电路设计

一、实验目的 掌握集成运放电压放大电路设计基本方法。 掌握基本仪器使用方法(电源、信号发生器、示波器)。 二、实验内容及结果 实验内容 基于集成运放设计一传感器信号采集电路。传感器输出信号在±50mV,频率为100Hz以内,模数转换器允许输入电压在0~5V,要求设计传感器与模数转换器之间的信号采集电路,实现传感器信号放大10倍,并适合模数转换器的输入。模数转换器的输入电阻为1KHz,设计电路时,可使用1KHz电阻作为信号采集电路负载,代替模数转换器。 实验具体要求如下: (1)确定电路形式,说明电压转

Safaearth的博客 4万+

PX4实战指南:通过遥控器通道映射实现多舵机PWM精准控制

本文详细介绍了通过PX4飞控的AUX PWM接口实现遥控器通道映射控制多舵机的实战指南。内容包括硬件选型与连接、软件参数配置、通道映射方法以及常见问题排查,帮助开发者精准实现无人机舵机PWM控制,适用于云台、机械臂等扩展功能开发。

ee345的博客 304

运筹系列39:ALNS使用

1. ALNS介绍 ALNS(Adaptive Large Neighborhood Search)是现在用的很多的启发式算法,发表于2010年。其基本思路是不断destroying和repairing问题。 定义XXX为问题III的可行解集,c(X)表示要优化的目标。我们从一个初始解x1出发,搜索N(x1)领域范围内的最优值x2,然后再搜索N(x2)范围内的最优值x3……,这是最优梯度下降法。 ...

kittyzc的博客 8178

传感器融合的智能演进:ST-MC-Workbench中霍尔与编码器的协同控制策略

本文探讨了ST-MC-Workbench中霍尔传感器与编码器的协同控制策略,通过传感器融合技术提升电机控制精度。文章详细介绍了分层处理架构、霍尔安装角度优化及编码器Z脉冲容错机制,展示了在新能源汽车和工业应用中的实际效果,为高精度位置检测提供了解决方案。

weixin_29159441的博客 484

【运筹优化】元启发式算法详解:(自适应)大邻域搜索算法(( Adaptive) Large Neighborhood Search,(A)LNS)+ 案例讲解&代码实现

在过去的15年中,基于大邻域搜索(LNS)和变异自适应大邻域搜索(ALNS)的启发式算法已经成为解决各种运输和调度问题的一些最成功的范例。大邻域搜索方法通过使用试探法来探索复杂的邻域(交替地破坏和修复解来逐渐改进初始解)。使用大邻域使得在每次迭代中找到更好的候选解成为可能,并因此遵循更有希望的搜索路径。本博客从大邻域搜索的一般框架出发,深入研究了自适应大邻域搜索,讨论了该框架的设计思想和性质。讨论了大邻域搜索方法在路由和调度中的应用。

知不足而奋进,望远山而前行 1万+

【上海大学计算机组成原理实验报告】七、程序转移机制

学习实现程序转移的硬件机制//掌握堆栈寄存器的使用//手动方式实现子程序调用转移过程//手动方式实现子程序返回转移过程//编程实现`OUT`寄存器交替显示`11`和`55`//若要求`11`和`55`各显示`50`次后停机,应该如何修改程序?//根据实验指导书的相关内容,实验箱系统的程序转移硬件机制在于,当`LDPC`有效时,如果此时`DUBS`上的值就是转移的目标地址,则此目标地址被打入`PC`,从而实现程序的转移;若`LDPC`为`0`是附带条件的,就形成“条件转移”。

HackerKevon的博客 2475

华为ENSP虚拟网络与本地物理网卡高效桥接实战指南

本文提供了一份详细的华为ENSP虚拟网络与本地物理网卡桥接实战指南。通过清晰的四步操作,帮助用户打破虚拟实验环境的“孤岛”限制,实现ENSP设备与真实局域网及互联网的互通,从而进行更真实的协议测试、软件升级和混合网络环境搭建。

qsc90123456的博客 538

ALNS算法——一、主逻辑结构解析

转载自:https://mp.weixin.qq.com/s/NenKRjYbsbQiOw3bMx8jSA 一、C++基础 1.1 C++中虚函数的作用 1、简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。 2、实现多态性,多态性是将接口与实现进行分离。 3、当基类指针指向一个子类对象,通过这个指针调用子类和基类同名成员函数的时候,基类声明为虚函数就会调子类的这个函数,不声明就会调用基类的。 1.2 纯虚函数 纯虚函数指明一个虚拟函数只是提供了一个可被子类型改写的接口。.

sky的博客 2424

YOLOv11改进 | 引入SFSConv空间频率选择卷积(含SFSC3k2二次创新),空间频率特征协同作用,检测性能全面提升

本文提出在YOLOv11中引入SFSConv空间频率选择卷积模块,通过显式分离和动态融合空间域与频率域特征,解决传统卷积对多尺度目标检测的局限性。SFSConv包含空间频率分离、动态权重融合和协同特征重建三个核心机制,并进一步创新提出SFSC3k2结构,通过双路频率分支增强特征协同作用。该改进显著提升了YOLOv11在遥感、医学等多尺度复杂场景下的检测性能,实验显示在微小目标检测任务中mAP提升5%-10%。代码实现展示了SFSConv模块的核心逻辑及其在PyTorch中的高效实现。

走向CTO的路上... 768

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

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

taozibaby的博客 3589

三步实现Java分布式追踪:像“开灯”一样简单

摘要: 本文通过三步实现Java分布式追踪: 引入依赖:配置Spring Cloud Sleuth+Zipkin,自动埋点无需代码侵入; 启动服务:REST接口自动生成Trace/Span ID,日志可验证; 可视化分析:通过Zipkin UI查看调用链耗时和拓扑关系。 亮点:AOP自动埋点、零业务代码修改、支持多服务链路追踪,助力快速定位性能瓶颈。适用于微服务诊断,生产环境可调整采样率平衡性能。(150字)

墨夶的博客 2711

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

自适应大邻域搜索算法(Adaptive Large Neighborhood Search——ALNS)

这又是一种基于邻域的搜索算法,邻域及其邻域的相关知识可以看这篇——禁忌搜索(TS——Tabu Search)与邻域搜索基础知识。之所以单独拿出来,是因为邻域搜索Neighborhood Search(NS)(本质也是一种启发式算法)也是一个奇妙的分支。 1.邻域搜索及其大家族 1.1 邻域搜索涉及概念 邻域搜索算法(或称为局部搜索算法)是一类非常常见的改进算法,在每次迭代时通过搜索当前解的“邻域”找到更优的解。邻域搜索算法设计中的关键是邻域结构的选择,即邻域定义的方式。根据以往的经验,邻域越大,局..

sinat_41348401的博客 1万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

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

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

Better.C的博客 7452

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ALNS自适应大邻域局部搜索算法

ALNS自适应大邻域局部搜索算法(Adaptive Large Neighborhood Search)是一种元启发式算法。ALNS算法结合了离散优化中的邻域搜索和元启发式算法的特点。元启发式算法是启发式算法的泛化形式,通常用于解决组合优化(也叫离散优化的问题,在有限个可能解的集合中找出最优解的优化问题)的问题,常见的元启发式算法包括遗传算法、模拟退火算法、粒子群优化算法等。启发式算法,是指通过启发式信息来指导搜索过程,以找到问题的近似最优解。

2303_77486313的博客 2726

提高邻域搜索效率

分享学术大牛vidal在解决CVRP(Capacitated vehicle routing problem)问题时通过改进解的表示以及搜索框架两个方面提升邻域搜索效率的方法。

qq_39289735的博客 1915

Python实现VRP常见求解算法——自适应大邻域搜索算法(ALNS)

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

Better.C的博客 1万+

如何快速掌握ALNS:Python自适应大邻域搜索算法的完整指南

ALNS(Adaptive Large Neighborhood Search)是一款强大的Python组合优化算法库,专为解决复杂的组合优化问题设计。通过灵活的启发式搜索框架,ALNS能在大型解空间中高效寻找近似最优解,广泛应用于物流调度、生产规划和资源分配等领域。本文将带你从安装到实战,全面掌握这个优化神器! ## ???? 什么是ALNS?核心功能解析 ALNS算法的核心在于**自适应邻域搜...

gitblog_00235的博客 664
上一篇: 【进阶一】Python实现MDCVRP常见求解算法——差分进化算法(DE)
下一篇: 【进阶二】Python实现VRPTW常见求解算法——遗传算法(GA)
Better.C
博客等级 码龄9年 1万+粉丝 72原创
评论 14
成就一亿技术人!
拼手气红包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、付费专栏及课程。

余额充值