【进阶三】Python实现(MD)HFVRPTW常见求解算法——蚁群算法(ACO)

基于遗传算法的具有时间窗的车辆路径问题解决方案的Python实现 立即下载

基于python语言,实现经典蚁群算法(ACO)对多车场(Multi-depot)、异构固定车辆(heterogeneous fixed fleet)、带有服务时间窗(time window)等限制约束的车辆路径规划问题((MD)HFVRPTW)进行求解。

往期优质资源

1. 适用场景

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

2. 求解效果

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

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

3. 代码分析

本算法继续采用将所有需求节点构造为一个有序列表的编码方式,并运用在邻域寻优过程中。当需要评估染色体质量时需采用split方法,在考虑车场、异构固定车队、服务时间窗等约束条件下,将有序列表分割为多个可行的车辆路径。split过程也是整个算法的核心,这里复现文末的参考文献中的算法3,并做了适当微调。整个算法的函数调用关系如下图(采用PyCallGraph绘制)。
在这里插入图片描述

4. 数据格式

以csv文件储存数据,其中demand.csv文件记录需求节点数据,共包含需求节点id,需求节点横坐标,需求节点纵坐标,需求量;depot.csv文件记录车场节点数据,共包含车场id,车场横坐标,车场纵坐标,车队类型,车辆容量,车辆速度,车辆数量,车辆固定成本,车辆单位变动成本,车辆最早开始服务时间,车辆最晚结束服务时间。需要注意的是:需求节点id应为整数,从0开始编号,车场节点id任意,但不可与需求节点id重复(建议以 ‘d’+int 形式,便于程序可视化路线)。 可参考github主页相关文件。

5. 分步实现

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

  • Sol()类,表示一个可行解
属性描述
node_id_list需求节点id有序排列集合
obj优化目标值
route_list车辆路径集合,对应MDVRPTW的解
timetable_list车辆节点访问时间集合,对应MDVRPTW的解
distance_of_routes总旅行距离
time_of_routes总时间
  • Demand()类,表示一个需求节点
属性描述
id物理节点id,需唯一
x_coord物理节点x坐标
y_coord物理节点y坐标
demand物理节点需求
start_time最早开始服务(被服务)时间
end_time最晚结束服务(被服务)时间
service_time需求节点服务时间
  • Vehicle()类,表示一个车队节点
属性描述
depot_id车辆归属的车场节点节点id,需唯一
x_coord车辆归属车场节点x坐标
y_coord车辆归属车场节点y坐标
type车辆类型
capacity车辆容量
free_speed车辆运营速度
fixed_cost车辆固定成本
variable_cost车辆变动成本
start_time最早开始服务时间
end_time最晚结束服务时间
  • Model()类,存储算法参数
属性描述
best_sol全局最优解,值类型为Sol()
sol_list蚁群集合,值类型为Sol()
demand_dict需求节点集合(字典),值类型为Demand()
vehicle_dict车队集合(字典),值类型为Vehicle()
vehicle_type_list车队id集合
demand_id_list需求节点id集合
distance_matrix节点距离矩阵
number_of_demands需求节点数量
opt_type优化目标类型,0:最小旅行距离,1:最小时间成本
popsize蚁群规模
alpha信息启发式因子
beta期望启发式因子
Q信息素总量
rho信息素挥发系数
tau网络弧信息素
tau0路径初始信息素

(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:
            demand = Demand()
            demand.id = int(row['id'])
            demand.x_coord = float(row['x_coord'])
            demand.y_coord = float(row['y_coord'])
            demand.demand = float(row['demand'])
            demand.start_time=float(row['start_time'])
            demand.end_time=float(row['end_time'])
            demand.service_time=float(row['service_time'])
            model.demand_dict[demand.id] = demand
            model.demand_id_list.append(demand.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:
            vehicle = Vehicle()
            vehicle.depot_id = row['depot_id']
            vehicle.x_coord = float(row['x_coord'])
            vehicle.y_coord = float(row['y_coord'])
            vehicle.type = row['vehicle_type']
            vehicle.capacity=float(row['vehicle_capacity'])
            vehicle.free_speed=float(row['vehicle_speed'])
            vehicle.numbers=float(row['number_of_vehicle'])
            vehicle.fixed_cost=float(row['fixed_cost'])
            vehicle.variable_cost=float(row['variable_cost'])
            vehicle.start_time=float(row['start_time'])
            vehicle.end_time=float(row['end_time'])
            model.vehicle_dict[vehicle.type] = vehicle
            model.vehicle_type_list.append(vehicle.type)

(3)计算距离矩阵,初始化路径信息素

def calDistanceMatrix(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 = 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.tau[from_node_id, to_node_id] = model.tau0
            model.tau[to_node_id, from_node_id] = model.tau0
        for _, vehicle in model.vehicle_dict.items():
            dist = sqrt((model.demand_dict[from_node_id].x_coord - vehicle.x_coord) ** 2
                             + (model.demand_dict[from_node_id].y_coord - vehicle.y_coord) ** 2)
            model.distance_matrix[from_node_id, vehicle.type] = dist
            model.distance_matrix[vehicle.type, from_node_id] = dist

(4)分割路径
split过程采用标号法最短路思想,为了避免在搜索过程中产生大量劣质节点标签,通过一定规则删除劣质标签:根据帕累托删除被支配的标签;根据剩余容量与剩余需求决定是否生成新标签。
在搜索过程中需要计算可能车辆路径的成本(时间成本或距离成本),如果采用时间成本,这里为了简化,只计算旅行距离成本,忽略了等待时间成本。但在计算适应度部分是严格按照时间成本内容计算的(旅行时间成本+等待时间成本)。

"检查路径是否满足时间要求,不满足要求则不会产生新的标签"
def checkTimeWindow(route,model,vehicle):
    timetable=[]
    departure=0
    for i in range(len(route)):
        if i == 0:
            next_node_id = route[i + 1]
            travel_time = int(model.distance_matrix[vehicle.type, next_node_id] /vehicle.free_speed)
            departure = max(0, model.demand_dict[next_node_id].start_time - travel_time)
            timetable.append((int(departure), int(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 = int(model.distance_matrix[last_node_id, current_node_id] / vehicle.free_speed)
            arrival = max(timetable[-1][1] + travel_time, current_node.start_time)
            departure = arrival + current_node.service_time
            timetable.append((int(arrival), int(departure)))
            if departure > current_node.end_time:
                departure = float('inf')
                break
        else:
            last_node_id = route[i - 1]
            travel_time = int(model.distance_matrix[last_node_id, vehicle.type] / vehicle.free_speed)
            departure = timetable[-1][1] + travel_time
            timetable.append((int(departure), int(departure)))
    if departure<vehicle.end_time:
        return True
    else:
        return False

"当产生新的标签W后,检查剩余的车辆容量之和是否能满足剩余未被检车的检点的总需求,如果总容量<总需求,则舍弃W,表明采用W后会导致解不可行"
"这也是减少无效标签的途径之一"
def checkResidualCapacity(residual_node_id_list,W,model):
    residual_fleet_capacity=0
    residual_demand = 0
    for node_id in residual_node_id_list:
        residual_demand+=model.demand_dict[node_id].demand
    for k,v_type in enumerate(model.vehicle_type_list):
        vehicle=model.vehicle_dict[v_type]
        residual_fleet_capacity+=(vehicle.numbers-W[k+4])*vehicle.capacity
    if residual_demand<=residual_fleet_capacity:
        return True
    else:
        return False

"由于标号法会产生大量标签,为了降标签数量,减少对劣质标签的搜索,在插入新标签时根据帕累托,删除支配解"
def updateNodeLabels(label_list,W,number_of_lables):
    new_label_list=[]
    if len(label_list)==0:
        number_of_lables += 1
        W[0] = number_of_lables
        new_label_list.append(W)
    else:
        for label in label_list:
            if W[3]<=label[3] and sum(W[4:])<=sum(label[4:]):
                if W not in new_label_list:
                    number_of_lables += 1
                    W[0] = number_of_lables
                    new_label_list.append(W)
            elif W[3]<=label[3] and sum(W[4:])>sum(label[4:]):
                new_label_list.append(label)
                if W not in new_label_list:
                    number_of_lables += 1
                    W[0] = number_of_lables
                    new_label_list.append(W)
            elif W[3]>label[3] and sum(W[4:])<sum(label[4:]):
                new_label_list.append(label)
                if W not in new_label_list:
                    number_of_lables += 1
                    W[0] = number_of_lables
                    new_label_list.append(W)
            elif W[3]>label[3] and sum(W[4:])>=sum(label[4:]):
                new_label_list.append(label)
    return new_label_list,number_of_lables

"根据标号法的求解结果,从中提取出各车辆路径"
def extractRoutes(V,node_id_list,model):
    route_list = []
    min_obj=float('inf')
    pred_label_id=None
    v_type=None
    # search the min cost label of last node of the node_id_list
    for label in V[model.number_of_demands-1]:
        if label[3]<=min_obj:
            min_obj=label[3]
            pred_label_id=label[1]
            v_type=label[2]
    # generate routes by pred_label_id
    route=[node_id_list[-1]]
    indexs=list(range(0,model.number_of_demands))[::-1]
    start=1
    while pred_label_id!=1:
        for i in indexs[start:]:
            stop=False
            for label in V[i]:
                if label[0]==pred_label_id:
                    stop=True
                    pred_label_id=label[1]
                    start=i
                    v_type_=label[2]
                    break
            if not stop:
                route.insert(0,node_id_list[i])
            else:
                route.insert(0,v_type)
                route.append(v_type)
                route_list.append(route)
                route=[node_id_list[i]]
                v_type=v_type_
    route.insert(0,v_type)
    route.append(v_type)
    route_list.append(route)
    return route_list

"采用标号法对node_id_list进行分割,得到车辆路径"
def splitRoutes(node_id_list,model):
    """
    V: dict,key=id,value=[n1,n2,n3,n4,n5,....]
        id:node_id_list的索引
        n1: 当前标签的生成次序
        n2: 生成当前标签的前一个标签的id
        n3: 当前标签对应的车辆类型
        n4: 当前路径的费用,对应与优化目标,当优化目标为旅行时间时,这里为简化计算只考虑节点间的旅行时间,舍去了等待时间
        n5-: 截止到当前标签,各类型车辆的使用数量
    这里采用先搜索车辆集合再搜索标签集合的方法,与原文是相反的"
        假设有a个标签,n个车需要搜索
            若按照原文的搜索顺序:对于任意一个label,都要判断当前路径对于n个车是否满足时间窗要求,搜索次数=a*n;
            若按照本文的搜索顺序。对于任意一个车辆类型,若路径不满足时间窗要求则不进行标签搜索,因此搜索次数应<a*n
    """
    V={i:[] for i in model.demand_id_list}
    V[-1]=[[0]*(len(model.vehicle_type_list)+4)] # -1表示虚拟车场的索引
    V[-1][0][0]=1 # 虚拟车场的标签id为1
    V[-1][0][1]=1 # 虚拟车场的标签的前向标签也为1
    number_of_lables=1
    for i in range(model.number_of_demands):
        n_1=node_id_list[i]
        j=i
        load=0
        distance={v_type:0 for v_type in model.vehicle_type_list}
        while True:
            n_2=node_id_list[j]
            load=load+model.demand_dict[n_2].demand
            stop = False
            for k,v_type in enumerate(model.vehicle_type_list):
                vehicle=model.vehicle_dict[v_type]
                if i == j:
                    distance[v_type]=model.distance_matrix[v_type,n_1]+model.distance_matrix[n_1,v_type]
                else:
                    n_3=node_id_list[j-1]
                    distance[v_type]=distance[v_type]-model.distance_matrix[n_3,v_type]+model.distance_matrix[n_3,n_2]\
                                     +model.distance_matrix[n_2,v_type]
                route=node_id_list[i:j+1]
                route.insert(0,v_type)
                route.append(v_type)
                if not checkTimeWindow(route,model,vehicle): # 检查时间窗,只有满足时间窗才有可能生成新的标签,否则跳过
                    continue
                for id,label in enumerate(V[i-1]):
                    if load<=vehicle.capacity and label[k+4]<vehicle.numbers:
                        stop=True
                        "计算路径成本,这里计算旅行时间成本时,只考虑节点间的旅行时间,暂不考虑等待时间成本"
                        if model.opt_type==0:
                            cost=vehicle.fixed_cost+distance[v_type]*vehicle.variable_cost
                        else:
                            cost=vehicle.fixed_cost+distance[v_type]/vehicle.free_speed*vehicle.variable_cost
                        "由于label是W的前向标签,因此可以在label的基础上生成W"
                        W=deepcopy(label)
                        "将W的前向标签id设置为label的id"
                        W[1]=V[i-1][id][0]
                        "设置W使用的车辆类型"
                        W[2]=v_type
                        "在label的基础上更新W的cost"
                        W[3]=W[3]+cost
                        "在label的基础上更新使用的车辆数"
                        W[k+4]=W[k+4]+1
                        "检车剩余容量约束,判断是否有可能将W作为当前节点的新的标签"
                        if checkResidualCapacity(node_id_list[j+1:],W,model):
                            "根据帕累托将W插入到当前节点的标签列表中,同时删除被支配标签"
                            label_list,number_of_lables=updateNodeLabels(V[j],W,number_of_lables)
                            V[j]=label_list
            j+=1
            if j>=len(node_id_list) or stop==False:
                break
    if len(V[model.number_of_demands-1])>0:
        route_list=extractRoutes(V, node_id_list, model)
        return route_list
    else:
        print("Failed to split the node id list because of the insufficient capacity")
        return None

(5)适应度计算
对于解的评价可采用旅行时间成本或旅行距离成本,关于某一条车辆路径的成本计算如下:

  • 距离成本=车辆固定成本+旅行距离*变动成本
  • 时间成本=车辆固定成本+(旅行时间+等待时间)*变动成本

这里认为单位距离成本=单位旅行时间成本=单位等待时间成本

"计算解的成本,这里对于时间成本包含了节点间旅行时间以及节点处的等待时间"
def calTravelCost(route_list,model):
    timetable_list=[]
    distance_of_routes=0
    time_of_routes=0
    obj=0
    for route in route_list:
        timetable=[]
        vehicle=model.vehicle_dict[route[0]]
        travel_distance=0
        travel_time=0
        v_type = route[0]
        free_speed=vehicle.free_speed
        fixed_cost=vehicle.fixed_cost
        variable_cost=vehicle.variable_cost
        for i in range(len(route)):
            if i == 0:
                next_node_id=route[i+1]
                travel_time_between_nodes=model.distance_matrix[v_type,next_node_id]/free_speed
                departure=max(0,model.demand_dict[next_node_id].start_time-travel_time_between_nodes)
                timetable.append((int(departure),int(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_between_nodes=model.distance_matrix[last_node_id,current_node_id]/free_speed
                arrival=max(timetable[-1][1]+travel_time_between_nodes,current_node.start_time)
                departure=arrival+current_node.service_time
                timetable.append((int(arrival),int(departure)))
                travel_distance += model.distance_matrix[last_node_id, current_node_id]
                travel_time += model.distance_matrix[last_node_id, current_node_id]/free_speed+\
                                + max(current_node.start_time - arrival, 0)
            else:
                last_node_id = route[i - 1]
                travel_time_between_nodes = model.distance_matrix[last_node_id,v_type]/free_speed
                departure = timetable[-1][1]+travel_time_between_nodes
                timetable.append((int(departure),int(departure)))
                travel_distance += model.distance_matrix[last_node_id,v_type]
                travel_time += model.distance_matrix[last_node_id,v_type]/free_speed
        distance_of_routes+=travel_distance
        time_of_routes+=travel_time
        if model.opt_type==0:
            obj+=fixed_cost+travel_distance*variable_cost
        else:
            obj += fixed_cost + travel_time *variable_cost
        timetable_list.append(timetable)
    return timetable_list,time_of_routes,distance_of_routes,obj

def calObj(sol,model):
    best_sol=Sol()
    best_sol.obj=float('inf')
    number_of_split_failures=0
    # calculate travel distance and travel time
    ret = splitRoutes(sol.node_id_list, model)
    if ret is not None:
        sol.route_list = ret
        sol.timetable_list, sol.time_of_routes, sol.distance_of_routes, sol.obj = calTravelCost(sol.route_list, model)
    else:
        number_of_split_failures += 1
        sol.obj = 10**5

(6)位置更新

def movePosition(model):
    sol_list=[]
    local_sol=Sol()
    local_sol.obj=float('inf')
    for k in range(model.popsize):
        #随机初始化蚂蚁为止
        nodes_id=[int(random.randint(0,len(model.demand_id_list)-1))]
        all_nodes_id=deepcopy(model.demand_id_list)
        all_nodes_id.remove(nodes_id[-1])
        #确定下一个访问节点
        while len(all_nodes_id)>0:
            next_node_no=searchNextNode(model,nodes_id[-1],all_nodes_id)
            nodes_id.append(next_node_no)
            all_nodes_id.remove(next_node_no)
        sol=Sol()
        sol.node_id_list=nodes_id
        calObj(sol,model)
        sol_list.append(sol)
        if sol.obj<local_sol.obj:
            local_sol=deepcopy(sol)
    model.sol_list=deepcopy(sol_list)
    if local_sol.obj<model.best_sol.obj:
        model.best_sol=deepcopy(local_sol)

def searchNextNode(model,current_node_id,SE_List):
    prob=np.zeros(len(SE_List))
    for i,node_id in enumerate(SE_List):
        eta=1/model.distance_matrix[current_node_id,node_id]
        tau=model.tau[current_node_id,node_id]
        prob[i]=((eta**model.alpha)*(tau**model.beta))
    #采用轮盘法选择下一个访问节点
    cumsumprob=(prob/sum(prob)).cumsum()
    cumsumprob -= np.random.rand()
    next_node_id= SE_List[list(cumsumprob > 0).index(True)]
    return next_node_id

(7)信息素更新

def upateTau(model):
    rho=model.rho
    for k in model.tau.keys():
        model.tau[k]=(1-rho)*model.tau[k]
    #根据解的node_id_list属性更新路径信息素(TSP问题的解)
    for sol in model.sol_list:
        nodes_id=sol.node_id_list
        for i in range(len(nodes_id)-1):
            from_node_id=nodes_id[i]
            to_node_id=nodes_id[i+1]
            model.tau[from_node_id,to_node_id]+=model.Q/sol.obj

(8)绘制收敛曲线

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

(9)绘制车辆路线

def plotRoutes(model):
    for route in model.best_sol.route_list:
        x_coord=[model.vehicle_dict[route[0]].x_coord]
        y_coord=[model.vehicle_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.vehicle_dict[route[-1]].x_coord)
        y_coord.append(model.vehicle_dict[route[-1]].y_coord)
        plt.grid()
        if route[0]=='v1':
            plt.plot(x_coord,y_coord,marker='o',color='black',linewidth=0.5,markersize=5)
        elif route[0]=='v2':
            plt.plot(x_coord,y_coord,marker='o',color='orange',linewidth=0.5,markersize=5)
        elif route[0]=='v3':
            plt.plot(x_coord,y_coord,marker='o',color='r',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()

(10)输出结果

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

(11)主函数

def run(demand_file,depot_file,Q,tau0,alpha,beta,rho,epochs,opt_type,popsize):
    """
    :param demand_file: demand file path
    :param depot_file: depot file path
    :param Q:信息素总量
    :param tau0: 路径信息素初始值
    :param alpha:信息启发式因子
    :param beta:期望启发式因子
    :param rho:信息挥发因子
    :param epochs:迭代次数
    :param opt_type:优化类型:0:最小化车辆数,1:最小化行驶距离
    :param popsize:蚁群规模
    :return:
    """
    model=Model()
    model.opt_type=opt_type
    model.alpha=alpha
    model.beta=beta
    model.Q=Q
    model.tau0=tau0
    model.rho=rho
    model.popsize=popsize
    sol=Sol()
    sol.obj=float('inf')
    model.best_sol=sol
    history_best_obj = []
    readCSVFile(demand_file,depot_file,model)
    calDistanceMatrix(model)
    start_time=time.time()
    for ep in range(epochs):
        movePosition(model)
        upateTau(model)
        history_best_obj.append(model.best_sol.obj)
        print("%s/%s, best obj: %s, runtime: %s" % (ep + 1, epochs, model.best_sol.obj, time.time() - start_time))
    plotObj(history_best_obj)
    plotRoutes(model)
    outPut(model)

6. 完整代码

如有错误,欢迎交流。
代码和数据文件获取【私】

参考

  1. Order-first split-second methods for vehicle routing problems: A review
VRPTW-Column-Generation(Python)列生成算法求解VRPTW问题(Python) VRPTW-Column-Generation 列生成算法求解VRPTW问题 该资源适合学习VRP问题的同学 立即下载

相关推荐

GA-VRPTW-python版本遗传算法求解带时间窗的路径规划问题(Python版本)

1、完整代码,可直接运行 ,包运行(如有疑问可私信) 2、擅长领域:路径规划、机器学习、数据爬虫、数据分析处理等 3、该资源有较为详尽的注解,非常方便大家阅读与理解。 GA-VRPTW-python版本 遗传算法求解带时间窗的路径规划问题(Python版本) 该资源适用于研究路径规划的同学,以及研究遗传算法的同学

【进阶三】Python实现(MD)HFVRPTW常见求解算法——离散粒子群(DPSO)

基于python语言,实现经典遗传算法(GA)对多车场(Multi-depot)、异构固定车辆(heterogeneous fixed fleet)、带有服务时间窗(time window)等限制约束的车辆路径规划问题((MD)HFVRPTW)进行求解。 目录往期资料1. 适用场景2. 求解效果3. 代码分析4. 数据格式5. 分步实现6. 完整代码参考 往期资料 python实现6种智能算法求解CVRP问题 python实现7种智能算法求解MDVRP问题 python实现7种智能算法求解MDVRPT.

Better.C的博客 1539

InSAR数据获取实战指南:Sentinel-1、精密轨道与ALOS PALSAR DEM的下载与应用

本文详细介绍了InSAR数据获取的实战指南,重点解析Sentinel-1数据、精密轨道数据(OPOD)和ALOS PALSAR DEM的下载与应用技巧。通过实际案例和代码示例,帮助读者掌握数据筛选、下载加速、校验及多源数据协同使用的关键方法,提升地面形变监测的精度与效率。

weixin_29215815的博客 433

[基因遗传算法]进阶之六:VRP的进阶经典问题的解码如何写

这里是对车辆进行了限制?与VRPTW相比,其结构上的变化,应该只是解码过程的变化. 解码后的route_list结构不变,所以后续的求距离时间成本,和计算适应度方法,都是几乎不改变的. 因此,这里重点讨论 如何对MDVRPTW进行解码.例如:node_id_list=[3,4,2,0,1,9,8,7,6,5],分割为[ [3,4],[2,0,1,9,8],[7,6,5]]splitRoutes(node_id_list,model) :根据车容量限制要求,分割为多个route.各车场车辆总数满足实际需求。

panbaoran913的博客 1702

5分钟搞定Unity+Visual Studio开发环境配置(含C#游戏开发工作负载)

本文提供了一份详细的Unity与Visual Studio开发环境配置指南,帮助开发者在5分钟内完成C#游戏开发工作负载的设置。从Unity Hub安装到Visual Studio关键组件选择,再到常见问题排查,全面覆盖环境搭建的各个环节,显著提升游戏开发效率。

weixin_29014237的博客 249

SAP UI5 主题设置全解析:从启动参数到运行时切换、跨域白名单与事件监听

SAP UI5主题体系深度解析:从配置到切换的完整指南 摘要:SAP UI5主题机制远不止CSS换肤,其工程化实践涵盖启动配置、运行时API切换、跨库路径映射及安全管控等关键环节。通过bootstrap标签或URL参数设置初始主题,运行时可用Theming.setTheme无刷新切换。自定义主题需配置theme-roots路径,跨域加载需声明sap-allowed-theme-origins白名单。主题切换完成后会触发applied事件,适合执行视觉同步操作。该体系支持多品牌适配、集中式主题管理,在Fior

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 328

【进阶二】Python实现VRPTW常见求解算法——禁忌搜索(TS)

基于python语言,实现经典禁忌搜索算法(TS)对带有时间窗的车辆路径规划问题(VRPTW )进行求解。

Better.C的博客 4038

GLM-4本地部署的实战教程

本文主要介绍了GLM-4-9B本地部署的实战教程,希望对学习和使用大模型的同学们有所帮助。 文章目录 1. 前言 2. 配置环境 2.1 安装虚拟环境 2.2 安装依赖库 2.3 下载模型文件 3. 运行glm-4-9b-chat

herosunly的博客 25万+

Python实现ACO蚁群优化算法优化Catboost分类模型(CatBoostClassifier算法)项目实战

Python实现ACO蚁群优化算法优化Catboost分类模型(CatBoostClassifier算法)项目实战

张陈亚的博客 1125

YOLOv13改进策略【Backbone/轻量化】| 替换骨干网络 CVPR-2024 StarNet,超级精简高效的轻量化模块

本文记录的是。StarNet设计简洁,没有复杂的设计和精细调整的超参数,仅是一个 4 阶段的分层架构。并且其中能够在低维空间计算的同时考虑极高维的特征这一特性,进而提高模型精度。本文在替换骨干网络中配置了原论文中的starnet_s1starnet_s2starnet_s3和starnet_s4七种模型,以满足不同的需求。

Limiiiing的博客 671

Python爬虫教程:爬取法院司法拍卖数据全流程实战(附反爬+数据分析方案)

Python爬虫爬取法院司法拍卖数据的核心是模拟真人行为规避反爬+精准解析页面数据+合理处理数据。新手不用一开始就追求高级的反爬技巧和复杂的数据分析,先把基础的分页爬取和数据保存功能跑通,再逐步优化。我做的这个工具现在每周帮朋友爬取全国10个城市的法拍房数据,自动生成分析报告,他说这让他的投资决策效率提升了一倍。如果你们在开发过程中遇到问题,比如反爬失败、数据解析错误,都可以在评论区留言,我会尽力解答。后续我还会出一期爬取京东司法拍卖数据的教程,帮助大家获取更多的法拍数据来源。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2185

【路径规划】(4) 蚁群算法,附python完整代码

蚁群算法是一种用来寻找优化路径的概率型算法。将蚁群算法应用于解决优化问题的基本思路为:用蚂蚁的行走路径表示待优化问题的可行解,整个蚂蚁群体的所有路径构成待优化问题的解空间。路径较短的蚂蚁释放的信息素量较多,随着时间的推进,较短的路径上累积的信息素浓度逐渐增高,选择该路径的蚂蚁个数也愈来愈多。最终,整个蚂蚁会在正反馈的作用下集中到最佳的路径上,此时对应的便是待优化问题的最优解

博观而约取,厚积而薄发 1万+

【雕爷学编程】Arduino动手做(75)---TTL转RS-485模块之二线制可以实现真正的多点双向通信

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来---小小的进步或是搞不掂的问题,希望能够抛砖引玉。 【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程) 实验七十五:TTL转RS-485模块 MAX485 RS485模块 MAX485 是一个8.

雕爷学编程 1万+

软件工具 | Python调用运筹优化求解器(一):以CVRP&VRPTW为例

以CVRP & VRPTW问题为例,介绍Python调用Gurobi,COPT,SCIP的方法。

Better.C的博客 7639

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【运筹优化】带时间窗约束的车辆路径规划问题(VRPTW)详解 + Python 调用 Gurobi 建模求解

车辆路径规划问题(Vehicle Routing Problem,VRP)一般指的是:对一系列发货点和收货点,组织调用一定的车辆,安排适当的行车路线,使车辆有序地通过它们,在满足指定的约束条件下(例如:货物的需求量与发货量,交发货时间,车辆容量限制,行驶里程限制,行驶时间限制等),力争实现一定的目标(如车辆空驶总里程最短,运输总费用最低,车辆按一定时间到达,使用的车辆数最小等)。下图给出了一个简单的VRP的例子最基本的VRP问题叫做带容量约束的车辆路径规划问题(Capacitated Vehicle Rou

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

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

VRPTW

带时间窗的VRP问题是在该基础上,还需要满足服务时间约束,即配送人员需要在一定的时间窗内到达客户需求点进行服务。带时间窗的VRP问题分为硬时间窗和软时间窗两种,硬时间窗是车辆一定要在时间窗范围内到达指定用户处,不能早于时间窗要求的最早时间,也不能晚于时间窗的最晚时间;VRP问题一般是指从物流配送中心用多辆车向多个客户需求点送货,每个客户需求点的位置和需求量是已知的,车辆的最大载质量是一定的,要求合理安排配送路线使得目标函数最优,并且满足以下条件:每个客户需求点只能被一辆车访问,并且只能访问一次;

FanSunshineboy的博客 2936

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

多目标遗传算法NSGAII求解环境经济调度(Python代码实现)

多目标遗传算法NSGAII求解环境经济调度(Python代码实现)

weixin_66436111的博客 1120

蚁群算法Python实现

蚁群算法Python实现

abc1234564546的博客 6334

蚁群算法.python代码

# -*- coding: cp936 -*- import random import numpy as np import copy import sys """蚁群算法计算过程如下: (1)初始化。 (2)为每只蚂蚁选择下一个节点。 (3)更新信息素矩阵。 (4)检查终止条件 如果达到最大代数MAX_GEN,算法终止,转到第(5)步;否则,重新初始化所有的蚂蚁的Delt矩阵所有元素初始化为0,Tabu表清空, Allowed表中加入所有的城市节点。随机选择它们的起始位置(也可以人工指定)。

肉夹馍的博客 3018

【进阶三】Python实现(MD)HFVRPTW常见求解算法——遗传算法(GA)

基于python语言,实现经典遗传算法(GA)对多车场(Multi-depot)、异构固定车辆(heterogeneous fixed fleet)、带有服务时间窗(time window)等限制约束的车辆路径规划问题((MD)HVRPTW)进行求解。

Better.C的博客 3942

Python实现VRP常见求解算法——离散粒子群(DPSO)

基于python语言,实现经典粒子群算法(DPSO)对车辆路径规划问题(CVRP)进行求解。

Better.C的博客 6227

智能算法系列之蚁群算法(详细补充版)

本篇是[智能算法(Python复现)]专栏的第六篇文章,主要是对蚁群算法的补充。在上篇博客中对蚁群算法的原理进行了简单的介绍,并用`python`实现蚁群算法在求函数极值方面的应用,但仔细研读一番发现重点没有突出来,而且与原始`TSP`问题中的蚁群算法又较大区别,感觉只涉及到蚁群算法的外壳,并没有触及灵魂。因此,在本篇中对蚁群算法在求函数极值方面的应用进行一个详细补充,并尽可能的触及蚁群算法的灵魂。

夏小悠的博客 1018

python实现蚁群算法

蚁群算法(Ant Colony Optimization,ACO)是一种基于蚂蚁在寻找食物时的行为而发展起来的启发式算法。蚁群算法是一种群体智能算法,它模拟了蚂蚁在寻找食物时的行为,通过多个个体之间相互合作、信息交流来寻找最优解。它的主要思想是通过模拟蚂蚁在寻找食物时释放信息素的过程,让蚂蚁们在搜索空间中寻找最优解。在蚁群算法中,每只蚂蚁表示一个搜索的个体,它们根据信息素和启发式信息(例如距离、费用等)来选择下一步移动的位置,并在移动的过程中更新信息素。

weixin_37490132的博客 3584

蚁群算法(ant colony optimization, ACO)

1 原理介绍​ 蚁群算法(Ant Colony Algorithm)最初于1992年由意大利学者M.Dorigo等人提出,它是一种模拟自然界中真实蚁群觅食行为的仿生优化算法。研究发现:每只蚂蚁觅食时在走过的路线上会留下一种称为信息素的物质,蚂蚁之间靠感知这种物质的浓度进行信息传递。蚂蚁在选择路径时总是倾向于朝信息索浓度高的方向移动,而距离短的路径上走过的蚂蚁多,留下的信息素也多,后续蚂蚁选择它...

无崖子的博客 3714

nsga2算法_NSGA2 遗传算法解决多目标优化

遗传算法解决多目标优化问题NSGA-II进行多目标优化时,通常面临多个目标函数无法同时达到最优的情况,为了解决这一矛盾,引入Pareto-Optimality的概念Pareto-Optimality 通常,多目标优化的一般形式为: 经过处理,可以化为以下形式:其中f1(x),f2(x),...,fn(x)为目标函数,其全部都是求最小值的形式以下针对两个目标函数进行讨论: 有几个目标函数便为几维空间...

weixin_39548541的博客 4706
上一篇: 【进阶三】Python实现(MD)HFVRPTW常见求解算法——离散粒子群(DPSO)
下一篇: 【进阶三】Python实现(MD)HFVRPTW常见求解算法——差分进化算法(DE)
Better.C
博客等级 码龄9年 1万+粉丝 72原创
评论 5
成就一亿技术人!
拼手气红包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、付费专栏及课程。

余额充值