使用蚁群算法求解VRPTW问题

蚁群优化算法

蚁群算法(ACO)适合求解带时间窗的车辆路径优化问题(VRPTW),主要基于其仿生智能机制与问题特性的深度契合,具体体现在以下六个方面:

  1. 时间窗约束的自然映射

    • 信息素导向与时间窗兼容
      蚂蚁在路径选择时综合评估信息素(历史经验)和启发式信息(如距离/时间成本),可无缝嵌入时间窗惩罚函数。例如:

      • 早到等待或晚到惩罚可转化为启发式因子(如ηᵢⱼ = 1/(行驶时间+时间窗偏离惩罚))。
      • 信息素累积会优先强化满足时间窗的路径。
    • 动态调整能力
      信息素挥发机制(ρ参数)能逐步淘汰违反约束的路径,自适应聚焦可行解区域。

  2. 多目标协同优化

    • 帕累托前沿逼近
      ACO通过调整α(信息素权重)、β(启发式权重)平衡多个目标:
      p i j k ∝ [ τ i j ] α ⋅ [ η i j ] β ⋅ [ 时间窗满足度 ] γ p_{ij}^k \propto [τ_{ij}]^α \cdot [η_{ij}]^β \cdot [时间窗满足度]^γ pijk[τij]α[ηij]β[时间窗满足度]γ
      其中γ为时间窗权重,实现距离最短与时间合规的权衡。

    • 分层优化实践
      如先满足硬时间窗,再优化路径长度,可通过设计信息素更新规则实现(仅对可行解释放信息素)。

  3. 复杂约束的灵活处理

    • 禁忌表(Tabu List)扩展
      除记录已访问节点外,可加入:

      • 车辆剩余容量检查
      • 节点服务时间窗校验
      • 动态交通约束(如高峰时段限行)
    • 混合约束编码
      例如将时间窗违反量转化为目标函数惩罚项:

      \text{总成本} = \sum 距离 + λ \cdot \max(0, 到达时间 - 最晚时间)
      
  4. 动态环境适应性

    • 实时信息素更新
      突发情况(如某点临时关闭)可通过局部信息素重置快速响应,优于传统数学规划需重新建模。

    • 在线调参机制
      自适应调整α/β参数:初期高探索性(β主导),后期高开发性(α主导),提升收敛效率。

  5. 算法改进增强性能

    • 精英蚂蚁策略
      仅允许当代最优解更新信息素,加速高质量路径积累。

    • 局部搜索嵌入
      在ACO生成的解上应用2-opt*或Or-opt算法,针对性优化时间窗冲突片段。

    • 并行化架构
      分区域部署蚁群协作求解,适用于大规模VRPTW(如500+节点)。

Python实现ACO求解VRPTW问题

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'KaiTi', 'FangSong', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

class Customer:
    def __init__(self, id, x, y, demand, ready_time, due_time, service_time):
        self.id = id
        self.x = x
        self.y = y
        self.demand = demand
        self.ready_time = ready_time
        self.due_time = due_time
        self.service_time = service_time

    def __repr__(self) -> str:
        return str({
   
            "customer": self.id,
            "demand": self.demand,
            "ready_time": self.ready_time,
            "due_time": self.due_time,
            "service_time": self.service_time,
        })

    def __str__(self):
        return self.__repr__()


def generate_customers(n_customers):
    np.random.seed(47)
    customers = [Customer(0, 50, 50, 0, 0, 200, 0)]
    # 只生成1个客户点(总共有2个点:仓库+客户1)
    for i in range(1, n_customers):
        x = np.random.randint(10, 90)
        y = np.random.randint(10, 90)
        demand = np.random.randint(1, 3)
        ready_time = np.random.randint(0, 520)
        due_time = ready_time + np.random.randint(30, 1440)
        service_time = np.random.randint(5, 10)
        customers.append(Customer(i, x, y, demand, ready_time, due_time, service_time))
    for customer in customers:
        print(customer)
    return customers


class VRPTW_ACO:
    def __init__(self, customers, vehicle_capacity):
        self.customers = customers
        self.n = len(customers)
        self.vehicle_capacity = vehicle_capacity
        self.dist_matrix = self._calc_dist_matrix()
        self.pheromone = np.ones((self.n, self.n))

    def _calc_dist_matrix(self):
        dist = np.zeros((self.n, self.n))
        for i in range(self.n):
            for j in range(self.n):
                dx = customers[i].x - customers[j].x
                dy = customers[i].y - customers[j].y
                dist[i][j] = np.sqrt(dx**2 + dy**2)
        return dist

    def _time_feasible(self, route, new_customer):
        """时间窗检查"""
        temp_route = route + [new_customer]
        current_time = 0
        current_load = 0
        prev_customer = temp_route[0]

        # 检查起始点载重
        current_load += prev_customer.demand
        if current_load > self.vehicle_capacity:
            return False

        for i in range(1, len(temp_route)):
            curr_customer = temp_route[i]
            # 计算旅行时间
            travel_time = self.dist_matrix[prev_customer.id][curr_customer.id]
            arrival_time = current_time + travel_time

            # 检查到达时间是否超过最晚时间
            if arrival_time > curr_customer.due_time:
                return False

            # 计算服务开始时间(考虑等待)
            service_start = max(arrival_time, curr_customer.ready_time)
            # 更新当前时间为服务结束时间
            current_time = service_start + curr_customer.service_time
            
            # 更新载重
            current_load += curr_customer.demand
            if current_load > self.vehicle_capacity:
                return False

            prev_customer = curr_customer
        return True

    def run(self, n_ants, n_iterations):
        best_solution = None
        best_cost = float("inf")
        convergence_history = []  # 记录收敛历史

        for iteration in range(n_iterations):
            solutions = []
            for _ in range(n_ants):
                unvisited = set(range(1, self.n))
                routes = []
                current_route = [self.customers[0]]
                # max_attempts = 10 * self.n

                while unvisited:
                    # max_attempts -= 1
                    feasible = []
                    for c_id in list(unvisited):
                        c = self.customers[c_id]
                        if self._time_feasible(current_route, c):
                            pheromone = self.pheromone[current_route[-1].id][c.id]
                            heuristic = 1 / self.dist_matrix[current_route[-1].id][c.id]
                            feasible.append((c, pheromone**alpha * heuristic**beta))
                    
                    if not feasible:
                        routes.append(current_route + [self.customers[0]])
                        current_route = [self.customers[0]]
                        continue

                    total = sum(score for _, score in feasible)
                    probs = [score / total for _, score in feasible]
                    next_customer = feasible[np.random.choice(len(feasible), p=probs)][0]
                    current_route.append(next_customer)
                    unvisited.remove(next_customer.id)

                if len(current_route) > 1:
                    routes.append(current_route + [self.customers[0]])

                total_cost = 0
                for route in routes:
                    for i in range(len(route) - 1):
                        total_cost += self.dist_matrix[route[i].id][route[i + 1].id]
                solutions.append((routes, total_cost))

                if total_cost < best_cost:
                    best_solution = routes
                    best_cost = total_cost
            
            # 记录当前迭代的最优解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值