智能物流路径规划系统:核心算法实战详解

文章目录

第一章:智能物流路径规划系统概述

1.1 物流路径规划的核心问题

智能物流路径规划系统是现代物流管理的核心技术,主要解决以下核心问题:

  1. 最短路径问题:在路网中找到两点间的最短行驶距离或时间
  2. 车辆路径问题:为多辆配送车辆规划最优配送路线
  3. 旅行商问题:单一车辆访问多个点的最优顺序问题
  4. 带时间窗的路径规划:考虑客户时间约束的配送路线规划
  5. 动态路径规划:实时响应交通状况变化的路线调整

1.2 系统架构设计

典型的智能物流路径规划系统包含以下模块:

复制代码
┌─────────────────────────────────────────────────────┐
│                   用户交互层                         │
│            Web前端 + 移动端 + API接口               │
├─────────────────────────────────────────────────────┤
│                   业务逻辑层                         │
│     订单管理 │ 车辆调度 │ 路径规划 │ 费用计算       │
├─────────────────────────────────────────────────────┤
│                   算法引擎层                         │
│     基础算法 │ 优化算法 │ 实时计算 │ 仿真验证       │
├─────────────────────────────────────────────────────┤
│                   数据支撑层                         │
│   地图数据 │ 交通数据 │ 历史数据 │ 实时数据        │
└─────────────────────────────────────────────────────┘

1.3 关键技术指标

  • 路径长度:规划路线的总行驶距离
  • 时间成本:考虑交通状况的总行驶时间
  • 燃油消耗:基于车辆型号和路况的燃油成本
  • 客户满意度:按时交付率和时间窗满足度
  • 资源利用率:车辆装载率和驾驶员工作量均衡

第二章:基础路径规划算法原理与实现

2.1 Dijkstra算法:基础最短路径算法

Dijkstra算法是解决单源最短路径问题的经典算法,适用于非负权重的有向图。

python 复制代码
import heapq
from typing import Dict, List, Tuple, Optional

class DijkstraPathPlanner:
    """
    Dijkstra算法实现
    """
    
    def __init__(self, graph: Dict[int, List[Tuple[int, float]]]):
        """
        初始化路径规划器
        
        Args:
            graph: 邻接表表示的图,{节点: [(邻居节点, 权重), ...]}
        """
        self.graph = graph
    
    def find_shortest_path(self, start: int, end: int) -> Tuple[List[int], float]:
        """
        查找最短路径
        
        Returns:
            (路径节点列表, 最短距离)
        """
        # 初始化距离字典,所有节点距离设为无穷大
        distances = {node: float('inf') for node in self.graph}
        distances[start] = 0
        
        # 前驱节点字典,用于重建路径
        previous_nodes = {node: None for node in self.graph}
        
        # 优先队列(距离, 节点)
        priority_queue = [(0, start)]
        
        while priority_queue:
            current_distance, current_node = heapq.heappop(priority_queue)
            
            # 如果已经找到到当前节点的更短路径,跳过
            if current_distance > distances[current_node]:
                continue
            
            # 到达目标节点,提前结束
            if current_node == end:
                break
            
            # 遍历邻居节点
            for neighbor, weight in self.graph.get(current_node, []):
                distance = current_distance + weight
                
                # 如果找到更短路径,更新
                if distance < distances[neighbor]:
                    distances[neighbor] = distance
                    previous_nodes[neighbor] = current_node
                    heapq.heappush(priority_queue, (distance, neighbor))
        
        # 重建路径
        path = []
        current = end
        while current is not None:
            path.append(current)
            current = previous_nodes[current]
        
        path.reverse()
        
        # 如果路径起点不是start,说明没有找到路径
        if path[0] != start:
            return [], float('inf')
        
        return path, distances[end]
    
    def find_paths_to_all(self, start: int) -> Dict[int, Tuple[List[int], float]]:
        """
        计算从起点到所有其他节点的最短路径
        
        Returns:
            字典 {目标节点: (路径, 距离)}
        """
        results = {}
        for node in self.graph:
            if node != start:
                path, distance = self.find_shortest_path(start, node)
                if path:  # 如果找到路径
                    results[node] = (path, distance)
        return results

# 使用示例
if __name__ == "__main__":
    # 构建示例图(城市路网简化表示)
    road_network = {
        0: [(1, 4), (2, 2)],      # 节点0到节点1距离4,到节点2距离2
        1: [(3, 5), (4, 10)],     # 节点1到节点3距离5,到节点4距离10
        2: [(1, 1), (3, 8)],      # 节点2到节点1距离1,到节点3距离8
        3: [(4, 2)],              # 节点3到节点4距离2
        4: [(0, 7)]               # 节点4到节点0距离7
    }
    
    planner = DijkstraPathPlanner(road_network)
    
    # 查找从节点0到节点4的最短路径
    path, distance = planner.find_shortest_path(0, 4)
    print(f"最短路径: {path}")
    print(f"最短距离: {distance}")
    
    # 查找从节点0到所有节点的最短路径
    all_paths = planner.find_paths_to_all(0)
    for target, (path, dist) in all_paths.items():
        print(f"到节点{target}: 路径{path}, 距离{dist}")

2.2 A*算法:启发式搜索优化

A*算法在Dijkstra的基础上加入启发式函数,显著提高搜索效率。

python 复制代码
import heapq
from math import sqrt
from typing import Dict, List, Tuple, Callable

class AStarPathPlanner:
    """
    A*算法实现
    """
    
    def __init__(self, graph: Dict[int, List[Tuple[int, float]]], 
                 coordinates: Dict[int, Tuple[float, float]]):
        """
        初始化A*路径规划器
        
        Args:
            graph: 邻接表表示的图
            coordinates: 节点坐标字典 {节点ID: (x, y)}
        """
        self.graph = graph
        self.coordinates = coordinates
    
    def euclidean_distance(self, node1: int, node2: int) -> float:
        """
        计算两点间欧几里得距离(启发式函数)
        """
        x1, y1 = self.coordinates[node1]
        x2, y2 = self.coordinates[node2]
        return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
    
    def find_path(self, start: int, end: int, 
                  heuristic_func: Callable[[int, int], float] = None) -> Tuple[List[int], float]:
        """
        使用A*算法查找路径
        
        Args:
            heuristic_func: 启发式函数,默认使用欧几里得距离
        
        Returns:
            (路径节点列表, 路径总代价)
        """
        if heuristic_func is None:
            heuristic_func = self.euclidean_distance
        
        # 初始化
        g_score = {node: float('inf') for node in self.graph}  # 从起点到当前节点的实际代价
        g_score[start] = 0
        
        f_score = {node: float('inf') for node in self.graph}  # 估计的总代价 f(n) = g(n) + h(n)
        f_score[start] = heuristic_func(start, end)
        
        came_from = {node: None for node in self.graph}  # 记录路径
        
        open_set = [(f_score[start], start)]  # 优先队列
        
        while open_set:
            current_f, current_node = heapq.heappop(open_set)
            
            # 到达目标节点
            if current_node == end:
                # 重建路径
                path = []
                while current_node is not None:
                    path.append(current_node)
                    current_node = came_from[current_node]
                path.reverse()
                return path, g_score[end]
            
            # 遍历邻居
            for neighbor, weight in self.graph.get(current_node, []):
                # 计算从起点到neighbor的实际代价
                tentative_g_score = g_score[current_node] + weight
                
                # 如果找到更优路径
                if tentative_g_score < g_score[neighbor]:
                    # 更新路径
                    came_from[neighbor] = current_node
                    g_score[neighbor] = tentative_g_score
                    f_score[neighbor] = tentative_g_score + heuristic_func(neighbor, end)
                    
                    # 如果邻居不在开放列表中,加入
                    if not any(neighbor == node for _, node in open_set):
                        heapq.heappush(open_set, (f_score[neighbor], neighbor))
        
        # 没有找到路径
        return [], float('inf')

# 使用示例
if __name__ == "__main__":
    # 构建带坐标的图
    graph = {
        0: [(1, 1.5), (2, 2.0)],
        1: [(0, 1.5), (3, 3.0), (4, 4.5)],
        2: [(0, 2.0), (3, 2.5)],
        3: [(1, 3.0), (2, 2.5), (4, 1.0)],
        4: [(1, 4.5), (3, 1.0)]
    }
    
    # 节点坐标(模拟地图位置)
    coordinates = {
        0: (0, 0),
        1: (2, 3),
        2: (1, 1),
        3: (3, 2),
        4: (4, 4)
    }
    
    planner = AStarPathPlanner(graph, coordinates)
    
    # 查找路径
    path, cost = planner.find_path(0, 4)
    print(f"A*算法找到的路径: {path}")
    print(f"路径总代价: {cost}")

2.3 D*算法:动态环境路径规划

D*算法特别适用于动态环境中的路径规划,能够高效处理环境变化。

python 复制代码
class DStarPathPlanner:
    """
    D* Lite算法简化实现(动态A*)
    """
    
    def __init__(self, grid_size: Tuple[int, int], obstacles: List[Tuple[int, int]]):
        """
        初始化D*规划器
        
        Args:
            grid_size: 网格地图大小 (width, height)
            obstacles: 障碍物位置列表 [(x1, y1), (x2, y2), ...]
        """
        self.width, self.height = grid_size
        self.obstacles = set(obstacles)
        
        # 初始化网格代价
        self.cost_map = [[1.0 for _ in range(self.width)] for _ in range(self.height)]
        
        # 设置障碍物代价为无穷大
        for x, y in self.obstacles:
            self.cost_map[y][x] = float('inf')
    
    def get_neighbors(self, x: int, y: int) -> List[Tuple[int, int, float]]:
        """
        获取当前网格的邻居(8方向)
        
        Returns:
            列表 [(邻居x, 邻居y, 移动代价), ...]
        """
        neighbors = []
        directions = [
            (-1, -1, 1.414), (0, -1, 1.0), (1, -1, 1.414),
            (-1, 0, 1.0),                 (1, 0, 1.0),
            (-1, 1, 1.414),  (0, 1, 1.0),  (1, 1, 1.414)
        ]
        
        for dx, dy, cost in directions:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.width and 0 <= ny < self.height:
                # 检查是否为障碍物
                if (nx, ny) not in self.obstacles:
                    neighbors.append((nx, ny, cost * self.cost_map[ny][nx]))
        
        return neighbors
    
    def update_cost(self, x: int, y: int, new_cost: float):
        """
        更新网格代价(模拟环境变化)
        """
        if 0 <= x < self.width and 0 <= y < self.height:
            old_cost = self.cost_map[y][x]
            self.cost_map[y][x] = new_cost
            
            # 如果代价发生变化,需要重新规划受影响的部分
            if abs(new_cost - old_cost) > 0.01:
                return True
        
        return False
    
    def replan_path(self, start: Tuple[int, int], goal: Tuple[int, int], 
                   old_path: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
        """
        当环境变化时重新规划路径
        
        Returns:
            新的路径
        """
        # 简化的重新规划:从当前位置重新运行A*
        return self.find_path(start, goal)
    
    def find_path(self, start: Tuple[int, int], goal: Tuple[int, int]) -> List[Tuple[int, int]]:
        """
        使用A*算法查找路径(简化的D* Lite实现)
        """
        import heapq
        
        # 初始化
        open_set = []
        heapq.heappush(open_set, (0, start))
        
        came_from = {}
        g_score = {start: 0}
        f_score = {start: self.heuristic(start, goal)}
        
        while open_set:
            current_f, current = heapq.heappop(open_set)
            
            if current == goal:
                # 重建路径
                path = []
                while current in came_from:
                    path.append(current)
                    current = came_from[current]
                path.append(start)
                path.reverse()
                return path
            
            # 遍历邻居
            for nx, ny, move_cost in self.get_neighbors(current[0], current[1]):
                neighbor = (nx, ny)
                tentative_g_score = g_score[current] + move_cost
                
                if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g_score
                    f_score[neighbor] = tentative_g_score + self.heuristic(neighbor, goal)
                    
                    if not any(neighbor == item[1] for item in open_set):
                        heapq.heappush(open_set, (f_score[neighbor], neighbor))
        
        return []  # 没有找到路径
    
    def heuristic(self, a: Tuple[int, int], b: Tuple[int, int]) -> float:
        """
        启发式函数(对角线距离)
        """
        dx = abs(a[0] - b[0])
        dy = abs(a[1] - b[1])
        return (dx + dy) + (1.414 - 2) * min(dx, dy)

# 使用示例
if __name__ == "__main__":
    # 创建10x10的网格地图
    planner = DStarPathPlanner((10, 10), [(2, 2), (3, 3), (4, 4)])
    
    # 初始路径规划
    start = (0, 0)
    goal = (9, 9)
    path = planner.find_path(start, goal)
    print(f"初始路径: {path}")
    
    # 模拟环境变化(新增障碍物)
    planner.update_cost(5, 5, float('inf'))  # 在(5,5)处新增障碍物
    
    # 重新规划路径
    if path:
        # 从路径中的某个点开始重新规划
        current_position = path[3] if len(path) > 3 else start
        new_path = planner.replan_path(current_position, goal, path)
        print(f"重新规划后的路径: {new_path}")

2.4 RRT(快速探索随机树)算法

RRT算法适用于高维空间和非完整约束的路径规划。

python 复制代码
import random
import math
import matplotlib.pyplot as plt

class RRTPlanner:
    """
    快速探索随机树算法实现
    """
    
    def __init__(self, bounds: Tuple[float, float, float, float], 
                 obstacles: List[Tuple[float, float, float]]):
        """
        初始化RRT规划器
        
        Args:
            bounds: 搜索边界 (x_min, x_max, y_min, y_max)
            obstacles: 障碍物列表 [(x, y, radius), ...]
        """
        self.x_min, self.x_max, self.y_min, self.y_max = bounds
        self.obstacles = obstacles
        
        # 树结构:节点列表和边字典
        self.nodes = []  # 每个节点是(x, y)坐标
        self.parents = {}  # 记录每个节点的父节点索引
        self.edges = []  # 边列表 [(节点索引, 节点索引), ...]
    
    def random_sample(self) -> Tuple[float, float]:
        """
        在搜索空间内随机采样一个点
        """
        x = random.uniform(self.x_min, self.x_max)
        y = random.uniform(self.y_min, self.y_max)
        return (x, y)
    
    def nearest_node(self, point: Tuple[float, float]) -> int:
        """
        查找树中离给定点最近的节点
        
        Returns:
            最近节点的索引
        """
        if not self.nodes:
            return -1
        
        min_dist = float('inf')
        nearest_idx = -1
        
        for i, node in enumerate(self.nodes):
            dist = self.distance(node, point)
            if dist < min_dist:
                min_dist = dist
                nearest_idx = i
        
        return nearest_idx
    
    def steer(self, from_point: Tuple[float, float], 
              to_point: Tuple[float, float], 
              max_step: float = 1.0) -> Tuple[float, float]:
        """
        从from_point向to_point方向移动max_step距离
        """
        dist = self.distance(from_point, to_point)
        
        if dist <= max_step:
            return to_point
        
        # 计算方向向量
        dx = to_point[0] - from_point[0]
        dy = to_point[1] - from_point[1]
        
        # 归一化并乘以最大步长
        scale = max_step / dist
        new_x = from_point[0] + dx * scale
        new_y = from_point[1] + dy * scale
        
        return (new_x, new_y)
    
    def collision_free(self, point1: Tuple[float, float], 
                       point2: Tuple[float, float]) -> bool:
        """
        检查两点之间的直线是否与障碍物碰撞
        """
        # 简化检查:只检查终点是否在障碍物内
        for ox, oy, radius in self.obstacles:
            if self.distance(point2, (ox, oy)) <= radius:
                return False
        
        # 更精确的检查:检查线段是否与障碍物相交
        for ox, oy, radius in self.obstacles:
            # 计算点到线段的最短距离
            dist = self.point_to_line_distance((ox, oy), point1, point2)
            if dist <= radius:
                return False
        
        return True
    
    def point_to_line_distance(self, point: Tuple[float, float], 
                               line_start: Tuple[float, float], 
                               line_end: Tuple[float, float]) -> float:
        """
        计算点到线段的最短距离
        """
        x, y = point
        x1, y1 = line_start
        x2, y2 = line_end
        
        # 线段长度的平方
        l2 = (x2 - x1) ** 2 + (y2 - y1) ** 2
        
        if l2 == 0:
            # 线段退化为点
            return math.sqrt((x - x1) ** 2 + (y - y1) ** 2)
        
        # 计算投影参数
        t = max(0, min(1, ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / l2))
        
        # 投影点坐标
        projection_x = x1 + t * (x2 - x1)
        projection_y = y1 + t * (y2 - y1)
        
        # 返回点到投影点的距离
        return math.sqrt((x - projection_x) ** 2 + (y - projection_y) ** 2)
    
    def distance(self, point1: Tuple[float, float], point2: Tuple[float, float]) -> float:
        """
        计算两点间欧几里得距离
        """
        return math.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2)
    
    def build_tree(self, start: Tuple[float, float], goal: Tuple[float, float], 
                   max_iter: int = 1000, goal_sample_rate: float = 0.1) -> bool:
        """
        构建RRT树
        
        Returns:
            是否成功找到到目标的路径
        """
        # 添加起点
        self.nodes.append(start)
        self.parents[0] = -1  # 起点没有父节点
        
        for i in range(max_iter):
            # 以一定概率采样目标点,加速收敛
            if random.random() < goal_sample_rate:
                sample = goal
            else:
                sample = self.random_sample()
            
            # 找到最近节点
            nearest_idx = self.nearest_node(sample)
            if nearest_idx == -1:
                continue
            
            nearest_node = self.nodes[nearest_idx]
            
            # 向采样点方向生长
            new_node = self.steer(nearest_node, sample)
            
            # 检查碰撞
            if self.collision_free(nearest_node, new_node):
                # 添加新节点
                new_idx = len(self.nodes)
                self.nodes.append(new_node)
                self.parents[new_idx] = nearest_idx
                self.edges.append((nearest_idx, new_idx))
                
                # 检查是否到达目标附近
                if self.distance(new_node, goal) < 1.0:
                    # 添加目标点
                    goal_idx = len(self.nodes)
                    self.nodes.append(goal)
                    self.parents[goal_idx] = new_idx
                    self.edges.append((new_idx, goal_idx))
                    return True
        
        return False
    
    def get_path(self) -> List[Tuple[float, float]]:
        """
        从树中提取路径(从最后一个节点回溯到起点)
        """
        if not self.nodes:
            return []
        
        # 找到最后一个节点(应该是目标点)
        current_idx = len(self.nodes) - 1
        path = []
        
        while current_idx != -1:
            path.append(self.nodes[current_idx])
            current_idx = self.parents.get(current_idx, -1)
        
        path.reverse()
        return path
    
    def visualize(self, path: List[Tuple[float, float]] = None):
        """
        可视化RRT树和路径
        """
        plt.figure(figsize=(10, 10))
        
        # 绘制障碍物
        for ox, oy, radius in self.obstacles:
            circle = plt.Circle((ox, oy), radius, color='gray', alpha=0.5)
            plt.gca().add_patch(circle)
        
        # 绘制树
        for i, j in self.edges:
            x1, y1 = self.nodes[i]
            x2, y2 = self.nodes[j]
            plt.plot([x1, x2], [y1, y2], 'b-', alpha=0.3, linewidth=0.5)
        
        # 绘制节点
        nodes_x = [node[0] for node in self.nodes]
        nodes_y = [node[1] for node in self.nodes]
        plt.scatter(nodes_x, nodes_y, c='blue', s=10, alpha=0.5)
        
        # 绘制起点和终点
        if self.nodes:
            start = self.nodes[0]
            goal = self.nodes[-1]
            plt.scatter(start[0], start[1], c='green', s=100, marker='o', label='Start')
            plt.scatter(goal[0], goal[1], c='red', s=100, marker='x', label='Goal')
        
        # 绘制路径
        if path:
            path_x = [p[0] for p in path]
            path_y = [p[1] for p in path]
            plt.plot(path_x, path_y, 'r-', linewidth=2, label='Path')
        
        plt.xlim(self.x_min, self.x_max)
        plt.ylim(self.y_min, self.y_max)
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.title('RRT Path Planning')
        plt.legend()
        plt.grid(True, alpha=0.3)
        plt.axis('equal')
        plt.show()

# 使用示例
if __name__ == "__main__":
    # 定义搜索空间和障碍物
    bounds = (0, 10, 0, 10)  # x_min, x_max, y_min, y_max
    obstacles = [
        (3, 3, 1.0),
        (5, 5, 1.5),
        (7, 2, 0.8),
        (2, 7, 1.2)
    ]
    
    # 创建RRT规划器
    planner = RRTPlanner(bounds, obstacles)
    
    # 定义起点和终点
    start = (1, 1)
    goal = (9, 9)
    
    # 构建树
    success = planner.build_tree(start, goal, max_iter=500)
    
    if success:
        print("成功找到路径!")
        path = planner.get_path()
        print(f"路径节点数: {len(path)}")
        
        # 可视化
        planner.visualize(path)
    else:
        print("未找到路径")
        planner.visualize()

第三章:高级路径优化策略

3.1 遗传算法在车辆路径问题中的应用

python 复制代码
import random
import numpy as np
from typing import List, Tuple, Callable

class GeneticAlgorithmVRP:
    """
    遗传算法求解车辆路径问题
    """
    
    def __init__(self, distance_matrix: np.ndarray, demands: List[float],
                 vehicle_capacity: float, population_size: int = 100,
                 mutation_rate: float = 0.1, crossover_rate: float = 0.8,
                 elitism_count: int = 2):
        """
        初始化遗传算法
        
        Args:
            distance_matrix: 距离矩阵 [n+1 x n+1],0表示仓库
            demands: 每个客户点的需求量
            vehicle_capacity: 车辆容量
        """
        self.distance_matrix = distance_matrix
        self.demands = demands
        self.vehicle_capacity = vehicle_capacity
        self.num_customers = len(demands)
        
        # 遗传算法参数
        self.population_size = population_size
        self.mutation_rate = mutation_rate
        self.crossover_rate = crossover_rate
        self.elitism_count = elitism_count
        
        # 初始化种群
        self.population = self.initialize_population()
    
    def initialize_population(self) -> List[List[int]]:
        """
        初始化种群
        每个个体是一个客户点的排列,用0表示车辆分隔
        例如:[1,2,3,0,4,5,6,0,7,8]表示三辆车
        """
        population = []
        
        for _ in range(self.population_size):
            # 创建客户点列表(排除仓库0)
            customers = list(range(1, self.num_customers + 1))
            random.shuffle(customers)
            
            # 随机插入车辆分隔符0
            individual = []
            remaining_customers = customers.copy()
            
            while remaining_customers:
                # 随机决定这辆车服务多少客户
                max_for_this_vehicle = len(remaining_customers)
                if max_for_this_vehicle > 1:
                    num_for_this_vehicle = random.randint(1, max_for_this_vehicle)
                else:
                    num_for_this_vehicle = 1
                
                # 添加客户点到当前车辆路线
                individual.extend(remaining_customers[:num_for_this_vehicle])
                remaining_customers = remaining_customers[num_for_this_vehicle:]
                
                # 如果不是最后一辆车,添加分隔符
                if remaining_customers:
                    individual.append(0)
            
            population.append(individual)
        
        return population
    
    def decode_individual(self, individual: List[int]) -> List[List[int]]:
        """
        解码个体,得到车辆路线列表
        """
        routes = []
        current_route = [0]  # 从仓库出发
        
        for gene in individual:
            if gene == 0:
                # 车辆分隔符,结束当前路线
                current_route.append(0)  # 返回仓库
                routes.append(current_route)
                current_route = [0]  # 开始新路线
            else:
                current_route.append(gene)
        
        # 添加最后一条路线
        if len(current_route) > 1:
            current_route.append(0)
            routes.append(current_route)
        
        return routes
    
    def calculate_fitness(self, individual: List[int]) -> float:
        """
        计算适应度(路线总距离的倒数,距离越小适应度越高)
        """
        routes = self.decode_individual(individual)
        total_distance = 0.0
        
        for route in routes:
            # 计算单条路线的距离
            route_distance = 0.0
            for i in range(len(route) - 1):
                from_node = route[i]
                to_node = route[i + 1]
                route_distance += self.distance_matrix[from_node][to_node]
            
            total_distance += route_distance
            
            # 检查容量约束
            route_demand = sum(self.demands[node-1] for node in route if node != 0)
            if route_demand > self.vehicle_capacity:
                # 违反容量约束,增加惩罚
                total_distance += 1000 * (route_demand - self.vehicle_capacity)
        
        # 适应度是距离的倒数(加上小常数避免除零)
        return 1.0 / (total_distance + 1e-6)
    
    def selection(self, fitness_values: List[float]) -> List[int]:
        """
        轮盘赌选择
        """
        total_fitness = sum(fitness_values)
        probabilities = [f / total_fitness for f in fitness_values]
        
        # 计算累积概率
        cumulative_probabilities = []
        cumulative_sum = 0.0
        for prob in probabilities:
            cumulative_sum += prob
            cumulative_probabilities.append(cumulative_sum)
        
        # 选择
        selected_indices = []
        for _ in range(self.population_size - self.elitism_count):
            r = random.random()
            for i, cum_prob in enumerate(cumulative_probabilities):
                if r <= cum_prob:
                    selected_indices.append(i)
                    break
        
        return selected_indices
    
    def crossover(self, parent1: List[int], parent2: List[int]) -> Tuple[List[int], List[int]]:
        """
        顺序交叉(OX)
        """
        if random.random() > self.crossover_rate:
            return parent1.copy(), parent2.copy()
        
        # 选择交叉点
        size = len(parent1)
        start, end = sorted(random.sample(range(size), 2))
        
        # 创建子代
        child1 = [-1] * size
        child2 = [-1] * size
        
        # 复制交叉段
        child1[start:end] = parent1[start:end]
        child2[start:end] = parent2[start:end]
        
        # 填充剩余位置
        self.fill_child(child1, parent2, start, end)
        self.fill_child(child2, parent1, start, end)
        
        return child1, child2
    
    def fill_child(self, child: List[int], parent: List[int], start: int, end: int):
        """
        为子代填充剩余基因
        """
        size = len(child)
        parent_index = 0
        child_index = 0
        
        # 跳过交叉段
        while child_index < size and child[child_index] != -1:
            child_index += 1
        
        while child_index < size:
            # 找到parent中不在child中的基因
            while parent_index < size:
                gene = parent[parent_index]
                parent_index += 1
                
                # 检查是否在交叉段中
                if start <= parent_index - 1 < end:
                    continue
                
                # 检查是否已在child中
                if gene not in child:
                    child[child_index] = gene
                    child_index += 1
                    break
            
            # 移动到下一个空位
            while child_index < size and child[child_index] != -1:
                child_index += 1
    
    def mutation(self, individual: List[int]) -> List[int]:
        """
        变异操作:随机交换两个基因
        """
        if random.random() > self.mutation_rate:
            return individual.copy()
        
        mutated = individual.copy()
        
        # 选择两个不同的位置
        i, j = random.sample(range(len(mutated)), 2)
        
        # 确保不交换车辆分隔符(0)
        if mutated[i] != 0 and mutated[j] != 0:
            mutated[i], mutated[j] = mutated[j], mutated[i]
        
        return mutated
    
    def optimize(self, generations: int = 100) -> Tuple[List[int], float]:
        """
        执行遗传算法优化
        
        Returns:
            (最优个体, 最优适应度)
        """
        best_individual = None
        best_fitness = -float('inf')
        
        for generation in range(generations):
            # 计算适应度
            fitness_values = [self.calculate_fitness(ind) for ind in self.population]
            
            # 更新最优解
            current_best_fitness = max(fitness_values)
            if current_best_fitness > best_fitness:
                best_fitness = current_best_fitness
                best_individual = self.population[fitness_values.index(current_best_fitness)].copy()
            
            # 选择
            selected_indices = self.selection(fitness_values)
            
            # 保留精英
            elite_indices = sorted(
                range(len(fitness_values)), 
                key=lambda i: fitness_values[i], 
                reverse=True
            )[:self.elitism_count]
            
            # 创建新种群
            new_population = []
            
            # 添加精英
            for idx in elite_indices:
                new_population.append(self.population[idx].copy())
            
            # 交叉和变异
            while len(new_population) < self.population_size:
                # 选择父母
                parent1_idx = random.choice(selected_indices)
                parent2_idx = random.choice(selected_indices)
                
                parent1 = self.population[parent1_idx]
                parent2 = self.population[parent2_idx]
                
                # 交叉
                child1, child2 = self.crossover(parent1, parent2)
                
                # 变异
                child1 = self.mutation(child1)
                child2 = self.mutation(child2)
                
                # 添加到新种群
                new_population.append(child1)
                if len(new_population) < self.population_size:
                    new_population.append(child2)
            
            self.population = new_population
            
            # 输出进度
            if generation % 10 == 0:
                total_distance = 1.0 / best_fitness if best_fitness > 0 else float('inf')
                print(f"Generation {generation}: Best Distance = {total_distance:.2f}")
        
        return best_individual, best_fitness

# 使用示例
if __name__ == "__main__":
    # 示例:5个客户点的VRP问题
    num_customers = 5
    
    # 随机生成距离矩阵(0表示仓库,1-5表示客户点)
    np.random.seed(42)
    distance_matrix = np.random.rand(num_customers + 1, num_customers + 1) * 10
    
    # 对角线设为0(自己到自己的距离为0)
    np.fill_diagonal(distance_matrix, 0)
    
    # 对称化距离矩阵
    distance_matrix = (distance_matrix + distance_matrix.T) / 2
    
    # 随机生成需求量
    demands = np.random.rand(num_customers) * 10
    
    # 车辆容量
    vehicle_capacity = 15.0
    
    # 创建遗传算法求解器
    ga_solver = GeneticAlgorithmVRP(
        distance_matrix=distance_matrix,
        demands=demands,
        vehicle_capacity=vehicle_capacity,
        population_size=50,
        mutation_rate=0.2,
        crossover_rate=0.9,
        elitism_count=2
    )
    
    # 运行优化
    best_solution, best_fitness = ga_solver.optimize(generations=100)
    
    # 解码最优解
    routes = ga_solver.decode_individual(best_solution)
    
    print("\n最优解:")
    print(f"适应度: {best_fitness}")
    print(f"总距离: {1.0 / best_fitness if best_fitness > 0 else '无穷大'}")
    
    print("\n车辆路线:")
    for i, route in enumerate(routes):
        route_demand = sum(demands[node-1] for node in route if node != 0)
        route_distance = sum(
            distance_matrix[route[j]][route[j+1]] 
            for j in range(len(route)-1)
        )
        print(f"车辆{i+1}: {route} 需求量: {route_demand:.2f} 距离: {route_distance:.2f}")

3.2 蚁群算法优化

python 复制代码
class AntColonyOptimization:
    """
    蚁群算法求解旅行商问题
    """
    
    def __init__(self, distance_matrix: np.ndarray, 
                 num_ants: int = 20, alpha: float = 1.0, 
                 beta: float = 5.0, rho: float = 0.5, 
                 q: float = 100.0):
        """
        初始化蚁群算法
        
        Args:
            distance_matrix: 距离矩阵
            num_ants: 蚂蚁数量
            alpha: 信息素重要程度因子
            beta: 启发式信息重要程度因子
            rho: 信息素挥发系数
            q: 信息素强度
        """
        self.distance_matrix = distance_matrix
        self.num_cities = distance_matrix.shape[0]
        self.num_ants = num_ants
        self.alpha = alpha
        self.beta = beta
        self.rho = rho
        self.q = q
        
        # 初始化信息素矩阵
        self.pheromone = np.ones((self.num_cities, self.num_cities)) * 0.1
        
        # 计算启发式信息(距离的倒数)
        self.heuristic = 1.0 / (distance_matrix + np.eye(self.num_cities) * 1e-6)
    
    def construct_solution(self) -> List[List[int]]:
        """
        所有蚂蚁构造解
        """
        all_tours = []
        all_distances = []
        
        for ant in range(self.num_ants):
            # 随机选择起始城市
            start_city = np.random.randint(self.num_cities)
            
            # 构造路径
            tour = [start_city]
            unvisited = set(range(self.num_cities)) - {start_city}
            
            while unvisited:
                current_city = tour[-1]
                
                # 计算选择概率
                probabilities = self.calculate_probabilities(current_city, unvisited)
                
                # 根据概率选择下一个城市
                next_city = self.roulette_wheel_selection(list(unvisited), probabilities)
                
                tour.append(next_city)
                unvisited.remove(next_city)
            
            # 计算路径长度
            distance = self.calculate_tour_distance(tour)
            
            all_tours.append(tour)
            all_distances.append(distance)
        
        return all_tours, all_distances
    
    def calculate_probabilities(self, current_city: int, unvisited: set) -> np.ndarray:
        """
        计算从当前城市到未访问城市的转移概率
        """
        probabilities = []
        total = 0.0
        
        for city in unvisited:
            tau = self.pheromone[current_city, city] ** self.alpha
            eta = self.heuristic[current_city, city] ** self.beta
            probability = tau * eta
            probabilities.append(probability)
            total += probability
        
        # 归一化
        if total > 0:
            probabilities = [p / total for p in probabilities]
        else:
            # 如果所有概率都为0,使用均匀分布
            probabilities = [1.0 / len(unvisited)] * len(unvisited)
        
        return np.array(probabilities)
    
    def roulette_wheel_selection(self, cities: List[int], probabilities: np.ndarray) -> int:
        """
        轮盘赌选择下一个城市
        """
        r = np.random.random()
        cumulative_probability = 0.0
        
        for city, prob in zip(cities, probabilities):
            cumulative_probability += prob
            if r <= cumulative_probability:
                return city
        
        # 如果由于浮点误差没有选择任何城市,返回最后一个
        return cities[-1]
    
    def calculate_tour_distance(self, tour: List[int]) -> float:
        """
        计算路径总距离
        """
        distance = 0.0
        for i in range(len(tour)):
            from_city = tour[i]
            to_city = tour[(i + 1) % len(tour)]
            distance += self.distance_matrix[from_city, to_city]
        return distance
    
    def update_pheromone(self, tours: List[List[int]], distances: List[float]):
        """
        更新信息素
        """
        # 信息素挥发
        self.pheromone *= (1.0 - self.rho)
        
        # 信息素增强
        for tour, distance in zip(tours, distances):
            pheromone_delta = self.q / distance
            
            for i in range(len(tour)):
                from_city = tour[i]
                to_city = tour[(i + 1) % len(tour)]
                self.pheromone[from_city, to_city] += pheromone_delta
                self.pheromone[to_city, from_city] += pheromone_delta  # 对称矩阵
    
    def optimize(self, iterations: int = 100) -> Tuple[List[int], float]:
        """
        执行蚁群算法优化
        
        Returns:
            (最优路径, 最短距离)
        """
        best_tour = None
        best_distance = float('inf')
        
        for iteration in range(iterations):
            # 所有蚂蚁构造解
            tours, distances = self.construct_solution()
            
            # 更新最优解
            min_distance_idx = np.argmin(distances)
            if distances[min_distance_idx] < best_distance:
                best_distance = distances[min_distance_idx]
                best_tour = tours[min_distance_idx].copy()
            
            # 更新信息素
            self.update_pheromone(tours, distances)
            
            # 输出进度
            if iteration % 10 == 0:
                print(f"Iteration {iteration}: Best Distance = {best_distance:.2f}")
        
        return best_tour, best_distance

# 使用示例
if __name__ == "__main__":
    # 生成示例距离矩阵(10个城市)
    np.random.seed(42)
    num_cities = 10
    coordinates = np.random.rand(num_cities, 2) * 100
    
    # 计算欧几里得距离矩阵
    distance_matrix = np.zeros((num_cities, num_cities))
    for i in range(num_cities):
        for j in range(num_cities):
            if i != j:
                dist = np.sqrt(np.sum((coordinates[i] - coordinates[j]) ** 2))
                distance_matrix[i, j] = dist
    
    # 创建蚁群算法求解器
    aco_solver = AntColonyOptimization(
        distance_matrix=distance_matrix,
        num_ants=30,
        alpha=1.0,
        beta=3.0,
        rho=0.5,
        q=100.0
    )
    
    # 运行优化
    best_tour, best_distance = aco_solver.optimize(iterations=100)
    
    print(f"\n最优路径: {best_tour}")
    print(f"最短距离: {best_distance:.2f}")
    
    # 可视化结果
    plt.figure(figsize=(10, 6))
    
    # 绘制城市
    plt.scatter(coordinates[:, 0], coordinates[:, 1], c='red', s=100)
    
    # 绘制最优路径
    tour_coords = coordinates[best_tour]
    tour_coords = np.vstack([tour_coords, tour_coords[0]])  # 闭合路径
    
    plt.plot(tour_coords[:, 0], tour_coords[:, 1], 'b-', linewidth=2, alpha=0.7)
    
    # 标记城市编号
    for i, (x, y) in enumerate(coordinates):
        plt.text(x, y, str(i), fontsize=12, ha='center', va='center')
    
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.title(f'Ant Colony Optimization - Best Tour (Distance: {best_distance:.2f})')
    plt.grid(True, alpha=0.3)
    plt.axis('equal')
    plt.show()

第四章:多约束条件下的路径规划

4.1 带时间窗的车辆路径问题(VRPTW)

python 复制代码
class VRPTWSolver:
    """
    带时间窗的车辆路径问题求解器
    """
    
    def __init__(self, distance_matrix: np.ndarray, time_matrix: np.ndarray,
                 demands: List[float], time_windows: List[Tuple[float, float]],
                 service_times: List[float], vehicle_capacity: float,
                 vehicle_speed: float = 1.0, max_route_time: float = 8.0):
        """
        初始化VRPTW求解器
        
        Args:
            distance_matrix: 距离矩阵
            time_matrix: 时间矩阵(基于距离和速度计算)
            demands: 需求量
            time_windows: 时间窗列表 [(最早时间, 最晚时间), ...]
            service_times: 服务时间
            vehicle_capacity: 车辆容量
            vehicle_speed: 车辆速度(单位距离/单位时间)
            max_route_time: 最大路线时间
        """
        self.distance_matrix = distance_matrix
        self.time_matrix = time_matrix
        self.demands = demands
        self.time_windows = time_windows
        self.service_times = service_times
        self.vehicle_capacity = vehicle_capacity
        self.vehicle_speed = vehicle_speed
        self.max_route_time = max_route_time
        self.num_customers = len(demands)
    
    def check_time_window_feasibility(self, route: List[int], arrival_times: List[float]) -> bool:
        """
        检查路线的时间窗可行性
        """
        for i, node in enumerate(route):
            if node == 0:  # 仓库
                continue
            
            # 计算到达时间
            arrival_time = arrival_times[i]
            earliest, latest = self.time_windows[node-1]
            
            # 检查是否在时间窗内
            if arrival_time < earliest:
                # 早到需要等待
                arrival_time = earliest
            elif arrival_time > latest:
                # 晚到,不可行
                return False
            
            # 加上服务时间
            departure_time = arrival_time + self.service_times[node-1]
            
            # 更新到达下一个点的时间(如果存在下一个点)
            if i + 1 < len(route):
                next_node = route[i + 1]
                travel_time = self.time_matrix[node][next_node]
                arrival_times[i + 1] = departure_time + travel_time
        
        return True
    
    def calculate_route_cost(self, route: List[int]) -> Tuple[float, float, bool]:
        """
        计算路线成本(距离、时间、可行性)
        """
        total_distance = 0.0
        total_time = 0.0
        current_time = 0.0
        current_load = 0.0
        arrival_times = [0.0] * len(route)
        arrival_times[0] = current_time
        
        feasible = True
        
        for i in range(len(route) - 1):
            from_node = route[i]
            to_node = route[i + 1]
            
            # 更新距离
            total_distance += self.distance_matrix[from_node][to_node]
            
            # 更新负载
            if to_node != 0:  # 不是仓库
                current_load += self.demands[to_node-1]
            
            # 检查容量约束
            if current_load > self.vehicle_capacity:
                feasible = False
                break
            
            # 计算旅行时间
            travel_time = self.time_matrix[from_node][to_node]
            
            # 计算到达时间
            if to_node != 0:  # 客户点
                arrival_time = current_time + travel_time
                earliest, latest = self.time_windows[to_node-1]
                
                # 检查时间窗
                if arrival_time < earliest:
                    # 等待到最早时间
                    wait_time = earliest - arrival_time
                    arrival_time = earliest
                    total_time += wait_time
                elif arrival_time > latest:
                    # 超过最晚时间,不可行
                    feasible = False
                    break
                
                # 服务时间
                service_time = self.service_times[to_node-1]
                current_time = arrival_time + service_time
                total_time += travel_time + service_time
            else:
                # 返回仓库
                current_time += travel_time
                total_time += travel_time
            
            # 检查最大路线时间
            if total_time > self.max_route_time:
                feasible = False
                break
        
        return total_distance, total_time, feasible
    
    def local_search_improvement(self, routes: List[List[int]]) -> List[List[int]]:
        """
        局部搜索改进:2-opt优化
        """
        improved_routes = []
        
        for route in routes:
            if len(route) <= 3:  # 路线太短,无需优化
                improved_routes.append(route)
                continue
            
            improved = True
            while improved:
                improved = False
                best_distance, _, feasible = self.calculate_route_cost(route)
                
                for i in range(1, len(route) - 2):
                    for j in range(i + 1, len(route) - 1):
                        # 尝试2-opt交换
                        new_route = route[:i] + route[i:j+1][::-1] + route[j+1:]
                        new_distance, _, new_feasible = self.calculate_route_cost(new_route)
                        
                        if new_feasible and new_distance < best_distance:
                            route = new_route
                            best_distance = new_distance
                            improved = True
                            break
                    if improved:
                        break
            
            improved_routes.append(route)
        
        return improved_routes
    
    def solve(self, initial_routes: List[List[int]] = None) -> Tuple[List[List[int]], float, float]:
        """
        求解VRPTW问题
        
        Returns:
            (最优路线列表, 总距离, 总时间)
        """
        # 如果没有初始解,使用简单启发式构造
        if initial_routes is None:
            initial_routes = self.construct_initial_solution()
        
        # 初始评估
        total_distance = 0.0
        total_time = 0.0
        feasible = True
        
        for route in initial_routes:
            distance, time, route_feasible = self.calculate_route_cost(route)
            total_distance += distance
            total_time += time
            if not route_feasible:
                feasible = False
        
        if not feasible:
            print("初始解不可行,尝试修复...")
            initial_routes = self.repair_solution(initial_routes)
        
        # 局部搜索改进
        improved_routes = self.local_search_improvement(initial_routes)
        
        # 最终评估
        final_distance = 0.0
        final_time = 0.0
        
        for route in improved_routes:
            distance, time, feasible = self.calculate_route_cost(route)
            if not feasible:
                print("警告:改进后的路线仍然不可行")
            final_distance += distance
            final_time += time
        
        return improved_routes, final_distance, final_time
    
    def construct_initial_solution(self) -> List[List[int]]:
        """
        构造初始解:最紧时间窗优先插入法
        """
        # 按照时间窗宽度排序客户
        time_window_widths = []
        for i, (early, late) in enumerate(self.time_windows):
            width = late - early
            time_window_widths.append((i+1, width, early))  # 客户编号从1开始
        
        # 按时间窗宽度升序排序(最紧的优先)
        sorted_customers = sorted(time_window_widths, key=lambda x: (x[1], x[2]))
        
        routes = []
        unassigned = [customer[0] for customer in sorted_customers]
        
        while unassigned:
            # 创建新路线
            route = [0]  # 从仓库出发
            current_load = 0.0
            current_time = 0.0
            
            # 尝试插入客户
            to_remove = []
            for customer in unassigned:
                # 检查容量约束
                demand = self.demands[customer-1]
                if current_load + demand > self.vehicle_capacity:
                    continue
                
                # 计算插入成本
                insert_position, insert_cost = self.find_best_insertion(route, customer, current_time)
                
                if insert_position != -1:
                    # 插入客户
                    route.insert(insert_position, customer)
                    current_load += demand
                    
                    # 更新当前时间(简化处理)
                    _, new_time, feasible = self.calculate_route_cost(route)
                    if feasible:
                        current_time = new_time
                        to_remove.append(customer)
            
            # 完成路线,返回仓库
            route.append(0)
            
            # 从待分配列表中移除已分配的客户
            for customer in to_remove:
                unassigned.remove(customer)
            
            routes.append(route)
        
        return routes
    
    def find_best_insertion(self, route: List[int], customer: int, current_time: float) -> Tuple[int, float]:
        """
        找到最佳插入位置
        """
        best_position = -1
        best_cost = float('inf')
        
        for i in range(1, len(route)):
            # 尝试在每个位置插入
            test_route = route[:i] + [customer] + route[i:]
            distance, time, feasible = self.calculate_route_cost(test_route)
            
            if feasible:
                # 插入成本 = 新距离 - 旧距离
                old_distance, _, _ = self.calculate_route_cost(route)
                cost = distance - old_distance
                
                if cost < best_cost:
                    best_cost = cost
                    best_position = i
        
        return best_position, best_cost
    
    def repair_solution(self, routes: List[List[int]]) -> List[List[int]]:
        """
        修复不可行解
        """
        # 简化的修复策略:将违反约束的客户移动到新路线
        repaired_routes = []
        problematic_customers = []
        
        for route in routes:
            distance, time, feasible = self.calculate_route_cost(route)
            
            if feasible:
                repaired_routes.append(route)
            else:
                # 分析违反的约束
                # 这里简化处理:拆分为更小的路线
                if len(route) > 3:
                    # 尝试从中间拆分
                    mid = len(route) // 2
                    route1 = route[:mid] + [0]
                    route2 = [0] + route[mid:]
                    
                    # 检查可行性
                    feasible1 = self.calculate_route_cost(route1)[2]
                    feasible2 = self.calculate_route_cost(route2)[2]
                    
                    if feasible1:
                        repaired_routes.append(route1)
                    else:
                        # 进一步拆分或标记问题客户
                        problematic_customers.extend(route1[1:-1])
                    
                    if feasible2:
                        repaired_routes.append(route2)
                    else:
                        problematic_customers.extend(route2[1:-1])
                else:
                    # 路线太短但不可行,标记问题客户
                    problematic_customers.extend([c for c in route if c != 0])
        
        # 处理问题客户(简化:每个客户单独一条路线)
        for customer in problematic_customers:
            repaired_routes.append([0, customer, 0])
        
        return repaired_routes

# 使用示例
if __name__ == "__main__":
    # 生成示例数据
    np.random.seed(42)
    num_customers = 8
    
    # 距离矩阵(0表示仓库,1-8表示客户)
    distance_matrix = np.random.rand(num_customers + 1, num_customers + 1) * 50
    np.fill_diagonal(distance_matrix, 0)
    distance_matrix = (distance_matrix + distance_matrix.T) / 2
    
    # 时间矩阵(假设速度=1,时间=距离)
    time_matrix = distance_matrix.copy()
    
    # 需求量
    demands = np.random.rand(num_customers) * 10
    
    # 时间窗(8小时工作制)
    time_windows = []
    for i in range(num_customers):
        start = np.random.uniform(0, 6)  # 最早开始时间
        end = start + np.random.uniform(1, 3)  # 时间窗宽度1-3小时
        time_windows.append((start, end))
    
    # 服务时间
    service_times = np.random.rand(num_customers) * 0.5  # 0-0.5小时
    
    # 车辆参数
    vehicle_capacity = 30.0
    max_route_time = 8.0
    
    # 创建求解器
    solver = VRPTWSolver(
        distance_matrix=distance_matrix,
        time_matrix=time_matrix,
        demands=demands,
        time_windows=time_windows,
        service_times=service_times,
        vehicle_capacity=vehicle_capacity,
        max_route_time=max_route_time
    )
    
    # 求解
    routes, total_distance, total_time = solver.solve()
    
    print("VRPTW求解结果:")
    print(f"总距离: {total_distance:.2f}")
    print(f"总时间: {total_time:.2f}")
    print(f"使用车辆数: {len(routes)}")
    
    for i, route in enumerate(routes):
        distance, time, feasible = solver.calculate_route_cost(route)
        load = sum(demands[node-1] for node in route if node != 0)
        print(f"路线{i+1}: {route} 距离: {distance:.2f} 时间: {time:.2f} 负载: {load:.2f} 可行: {feasible}")

第五章:完整系统实现与性能优化

5.1 系统架构设计

python 复制代码
class LogisticsPathPlanningSystem:
    """
    智能物流路径规划系统
    """
    
    def __init__(self, config: dict):
        """
        初始化系统
        
        Args:
            config: 系统配置字典
        """
        self.config = config
        self.map_data = None
        self.vehicle_fleet = None
        self.order_pool = None
        
        # 算法模块
        self.shortest_path_planner = None
        self.vrp_solver = None
        self.dynamic_planner = None
        
        # 缓存
        self.route_cache = {}
        self.traffic_cache = {}
        
        # 性能监控
        self.metrics = {
            'planning_time': [],
            'route_length': [],
            'constraint_violations': []
        }
    
    def load_map_data(self, map_file: str):
        """
        加载地图数据
        """
        print(f"加载地图数据: {map_file}")
        # 这里可以连接OpenStreetMap、高德地图、百度地图等API
        # 或读取本地地图文件
        self.map_data = self.parse_map_file(map_file)
        
        # 初始化最短路径规划器
        graph = self.build_graph_from_map(self.map_data)
        self.shortest_path_planner = DijkstraPathPlanner(graph)
        
        print(f"地图加载完成,包含 {len(self.map_data['nodes'])} 个节点,{len(self.map_data['edges'])} 条边")
    
    def build_graph_from_map(self, map_data: dict) -> Dict[int, List[Tuple[int, float]]]:
        """
        从地图数据构建图结构
        """
        graph = {}
        
        for node_id, node_info in map_data['nodes'].items():
            graph[node_id] = []
        
        for edge in map_data['edges']:
            from_node = edge['from']
            to_node = edge['to']
            weight = edge.get('weight', 1.0)
            
            # 双向道路
            if edge.get('bidirectional', True):
                graph[from_node].append((to_node, weight))
                graph[to_node].append((from_node, weight))
            else:
                graph[from_node].append((to_node, weight))
        
        return graph
    
    def plan_route(self, start: int, end: int, 
                  constraints: dict = None) -> dict:
        """
        规划单一路径
        
        Args:
            start: 起点节点ID
            end: 终点节点ID
            constraints: 约束条件
            
        Returns:
            路径规划结果
        """
        start_time = time.time()
        
        # 检查缓存
        cache_key = f"{start}_{end}_{hash(str(constraints))}"
        if cache_key in self.route_cache:
            print(f"从缓存获取路径: {start} -> {end}")
            return self.route_cache[cache_key]
        
        # 根据约束选择算法
        if constraints and constraints.get('dynamic', False):
            # 动态路径规划
            path, distance = self.plan_dynamic_route(start, end, constraints)
        elif constraints and constraints.get('time_windows'):
            # 带时间窗的路径规划
            path, distance = self.plan_timed_route(start, end, constraints)
        else:
            # 基础最短路径
            path, distance = self.shortest_path_planner.find_shortest_path(start, end)
        
        # 计算预计时间
        estimated_time = self.estimate_travel_time(path, distance, constraints)
        
        # 构建结果
        result = {
            'path': path,
            'distance': distance,
            'estimated_time': estimated_time,
            'constraints': constraints,
            'planning_time': time.time() - start_time
        }
        
        # 缓存结果
        if len(self.route_cache) < self.config.get('max_cache_size', 1000):
            self.route_cache[cache_key] = result
        
        # 记录性能指标
        self.metrics['planning_time'].append(result['planning_time'])
        self.metrics['route_length'].append(distance)
        
        return result
    
    def plan_dynamic_route(self, start: int, end: int, constraints: dict) -> Tuple[List[int], float]:
        """
        规划动态路径(考虑实时交通)
        """
        print(f"规划动态路径: {start} -> {end}")
        
        # 获取实时交通数据
        traffic_data = self.get_traffic_data(start, end)
        
        # 调整图权重
        adjusted_graph = self.adjust_graph_for_traffic(
            self.shortest_path_planner.graph, 
            traffic_data
        )
        
        # 使用A*算法(考虑实时交通)
        temp_planner = AStarPathPlanner(
            graph=adjusted_graph,
            coordinates=self.map_data.get('coordinates', {})
        )
        
        return temp_planner.find_path(start, end)
    
    def adjust_graph_for_traffic(self, graph: dict, traffic_data: dict) -> dict:
        """
        根据交通数据调整图权重
        """
        adjusted_graph = {node: [] for node in graph}
        
        for node, edges in graph.items():
            for neighbor, weight in edges:
                # 获取交通影响因子
                traffic_key = f"{node}_{neighbor}"
                traffic_factor = traffic_data.get(traffic_key, 1.0)
                
                # 调整权重(交通拥堵时权重增加)
                adjusted_weight = weight * traffic_factor
                adjusted_graph[node].append((neighbor, adjusted_weight))
        
        return adjusted_graph
    
    def get_traffic_data(self, start: int, end: int) -> dict:
        """
        获取实时交通数据
        """
        # 这里可以连接实时交通API
        # 简化实现:模拟交通数据
        
        if not self.traffic_cache or time.time() - self.traffic_cache.get('timestamp', 0) > 300:
            # 每5分钟更新一次交通数据
            traffic_data = self.simulate_traffic_data()
            traffic_data['timestamp'] = time.time()
            self.traffic_cache = traffic_data
        
        return self.traffic_cache
    
    def simulate_traffic_data(self) -> dict:
        """
        模拟交通数据
        """
        traffic_data = {}
        
        # 模拟道路拥堵情况
        for edge in self.map_data['edges']:
            from_node = edge['from']
            to_node = edge['to']
            
            # 随机生成交通影响因子(1.0-3.0)
            # 1.0表示畅通,3.0表示严重拥堵
            traffic_factor = 1.0 + random.random() * 2.0
            
            # 早晚高峰模拟
            current_hour = time.localtime().tm_hour
            if 7 <= current_hour <= 9 or 17 <= current_hour <= 19:
                traffic_factor *= 1.5
            
            key = f"{from_node}_{to_node}"
            traffic_data[key] = traffic_factor
        
        return traffic_data
    
    def estimate_travel_time(self, path: List[int], distance: float, 
                            constraints: dict = None) -> float:
        """
        估计旅行时间
        """
        # 基础速度(km/h)
        base_speed = self.config.get('base_speed', 30.0)
        
        # 考虑交通影响
        traffic_factor = 1.0
        if constraints and constraints.get('consider_traffic', True):
            traffic_data = self.get_traffic_data(path[0], path[-1])
            
            # 计算路径平均交通影响
            total_factor = 0.0
            count = 0
            
            for i in range(len(path) - 1):
                from_node = path[i]
                to_node = path[i + 1]
                key = f"{from_node}_{to_node}"
                
                if key in traffic_data:
                    total_factor += traffic_data[key]
                    count += 1
            
            if count > 0:
                traffic_factor = total_factor / count
        
        # 调整速度
        adjusted_speed = base_speed / traffic_factor
        
        # 计算时间(小时)
        travel_time = distance / adjusted_speed
        
        return travel_time
    
    def batch_plan_routes(self, requests: List[dict]) -> List[dict]:
        """
        批量规划路径
        """
        results = []
        
        for request in requests:
            result = self.plan_route(
                start=request['start'],
                end=request['end'],
                constraints=request.get('constraints')
            )
            results.append(result)
        
        return results
    
    def optimize_vehicle_routes(self, orders: List[dict], 
                               vehicles: List[dict]) -> dict:
        """
        优化车辆路线(VRP问题)
        """
        print(f"优化车辆路线: {len(orders)}个订单, {len(vehicles)}辆车")
        
        start_time = time.time()
        
        # 构建距离矩阵
        distance_matrix = self.build_distance_matrix(orders, vehicles)
        
        # 提取需求和时间窗
        demands = [order['demand'] for order in orders]
        
        time_windows = []
        for order in orders:
            if 'time_window' in order:
                time_windows.append(order['time_window'])
            else:
                # 默认时间窗(全天)
                time_windows.append((0, 24))
        
        # 创建VRP求解器
        vrp_solver = GeneticAlgorithmVRP(
            distance_matrix=distance_matrix,
            demands=demands,
            vehicle_capacity=vehicles[0]['capacity'],  # 假设所有车容量相同
            population_size=50,
            mutation_rate=0.1,
            crossover_rate=0.8
        )
        
        # 求解
        best_solution, best_fitness = vrp_solver.optimize(generations=100)
        
        # 解码结果
        routes = vrp_solver.decode_individual(best_solution)
        
        # 分配车辆
        vehicle_assignments = []
        for i, route in enumerate(routes):
            if i < len(vehicles):
                vehicle_id = vehicles[i]['id']
                vehicle_assignments.append({
                    'vehicle_id': vehicle_id,
                    'route': route,
                    'distance': vrp_solver.calculate_route_cost(route)
                })
        
        result = {
            'assignments': vehicle_assignments,
            'total_distance': 1.0 / best_fitness if best_fitness > 0 else float('inf'),
            'planning_time': time.time() - start_time,
            'num_vehicles_used': len(vehicle_assignments)
        }
        
        print(f"路线优化完成,使用 {result['num_vehicles_used']} 辆车,总距离 {result['total_distance']:.2f}")
        
        return result
    
    def build_distance_matrix(self, orders: List[dict], vehicles: List[dict]) -> np.ndarray:
        """
        构建距离矩阵
        """
        # 所有点:仓库 + 订单点
        num_points = 1 + len(orders)  # 0: 仓库, 1-n: 订单点
        
        distance_matrix = np.zeros((num_points, num_points))
        
        # 计算仓库到各点的距离
        for i, order in enumerate(orders):
            # 仓库到订单点
            result = self.plan_route(0, order['location'])
            distance_matrix[0, i+1] = result['distance']
            distance_matrix[i+1, 0] = result['distance']
        
        # 计算订单点之间的距离
        for i in range(len(orders)):
            for j in range(i+1, len(orders)):
                result = self.plan_route(
                    orders[i]['location'], 
                    orders[j]['location']
                )
                distance_matrix[i+1, j+1] = result['distance']
                distance_matrix[j+1, i+1] = result['distance']
        
        return distance_matrix
    
    def get_performance_metrics(self) -> dict:
        """
        获取系统性能指标
        """
        metrics = {}
        
        # 规划时间统计
        planning_times = self.metrics['planning_time']
        if planning_times:
            metrics['avg_planning_time'] = np.mean(planning_times)
            metrics['max_planning_time'] = np.max(planning_times)
            metrics['min_planning_time'] = np.min(planning_times)
        
        # 路线长度统计
        route_lengths = self.metrics['route_length']
        if route_lengths:
            metrics['avg_route_length'] = np.mean(route_lengths)
            metrics['total_route_length'] = np.sum(route_lengths)
        
        # 缓存命中率
        if hasattr(self, 'cache_hits') and hasattr(self, 'cache_misses'):
            total = self.cache_hits + self.cache_misses
            if total > 0:
                metrics['cache_hit_rate'] = self.cache_hits / total
        
        return metrics
    
    def visualize_routes(self, routes: List[List[int]], title: str = "路线规划结果"):
        """
        可视化路线
        """
        if not self.map_data or 'coordinates' not in self.map_data:
            print("无法可视化:缺少坐标数据")
            return
        
        plt.figure(figsize=(12, 10))
        
        # 绘制地图节点
        coords = self.map_data['coordinates']
        node_x = [coords[node][0] for node in coords]
        node_y = [coords[node][1] for node in coords]
        
        plt.scatter(node_x, node_y, c='lightgray', s=10, alpha=0.5)
        
        # 绘制路线
        colors = ['red', 'blue', 'green', 'orange', 'purple', 'brown']
        
        for i, route in enumerate(routes):
            if len(route) < 2:
                continue
            
            color = colors[i % len(colors)]
            
            # 提取坐标
            route_x = [coords[node][0] for node in route if node in coords]
            route_y = [coords[node][1] for node in route if node in coords]
            
            # 绘制路线
            plt.plot(route_x, route_y, color=color, linewidth=2, 
                    marker='o', markersize=8, label=f'路线{i+1}')
            
            # 标记起点和终点
            if route_x:
                plt.scatter(route_x[0], route_y[0], color=color, 
                           s=200, marker='s', edgecolors='black', linewidth=2)
                plt.scatter(route_x[-1], route_y[-1], color=color, 
                           s=200, marker='*', edgecolors='black', linewidth=2)
        
        plt.xlabel('X坐标')
        plt.ylabel('Y坐标')
        plt.title(title)
        plt.legend()
        plt.grid(True, alpha=0.3)
        plt.axis('equal')
        plt.show()

# 使用示例
if __name__ == "__main__":
    # 系统配置
    config = {
        'base_speed': 40.0,  # 基础速度40km/h
        'max_cache_size': 1000,
        'traffic_update_interval': 300  # 5分钟更新一次交通数据
    }
    
    # 创建系统
    system = LogisticsPathPlanningSystem(config)
    
    # 加载地图数据(简化示例)
    # 实际应用中可以从文件或API加载
    mock_map_data = {
        'nodes': {
            0: {'name': '仓库', 'type': 'depot'},
            1: {'name': '客户A', 'type': 'customer'},
            2: {'name': '客户B', 'type': 'customer'},
            3: {'name': '客户C', 'type': 'customer'},
            4: {'name': '客户D', 'type': 'customer'},
            5: {'name': '客户E', 'type': 'customer'}
        },
        'edges': [
            {'from': 0, 'to': 1, 'weight': 5.0},
            {'from': 0, 'to': 2, 'weight': 8.0},
            {'from': 1, 'to': 2, 'weight': 3.0},
            {'from': 1, 'to': 3, 'weight': 7.0},
            {'from': 2, 'to': 4, 'weight': 6.0},
            {'from': 3, 'to': 4, 'weight': 4.0},
            {'from': 3, 'to': 5, 'weight': 9.0},
            {'from': 4, 'to': 5, 'weight': 5.0}
        ],
        'coordinates': {
            0: (0, 0),
            1: (2, 3),
            2: (5, 1),
            3: (7, 4),
            4: (8, 2),
            5: (10, 5)
        }
    }
    
    # 设置地图数据
    system.map_data = mock_map_data
    
    # 构建图
    graph = system.build_graph_from_map(mock_map_data)
    system.shortest_path_planner = DijkstraPathPlanner(graph)
    
    print("智能物流路径规划系统初始化完成")
    
    # 示例1:单一路径规划
    print("\n--- 示例1:单一路径规划 ---")
    result = system.plan_route(start=0, end=5)
    print(f"路径: {result['path']}")
    print(f"距离: {result['distance']:.2f} km")
    print(f"预计时间: {result['estimated_time']*60:.1f} 分钟")
    print(f"规划时间: {result['planning_time']*1000:.2f} ms")
    
    # 示例2:批量路径规划
    print("\n--- 示例2:批量路径规划 ---")
    requests = [
        {'start': 0, 'end': 3, 'constraints': {'consider_traffic': True}},
        {'start': 1, 'end': 4, 'constraints': {'consider_traffic': False}},
        {'start': 2, 'end': 5, 'constraints': {'time_windows': (8, 12)}}
    ]
    
    batch_results = system.batch_plan_routes(requests)
    for i, res in enumerate(batch_results):
        print(f"请求{i+1}: {requests[i]['start']} -> {requests[i]['end']}")
        print(f"  路径长度: {res['distance']:.2f} km")
        print(f"  规划时间: {res['planning_time']*1000:.2f} ms")
    
    # 示例3:车辆路径优化
    print("\n--- 示例3:车辆路径优化 ---")
    orders = [
        {'id': 1, 'location': 1, 'demand': 5.0, 'time_window': (8, 12)},
        {'id': 2, 'location': 2, 'demand': 8.0, 'time_window': (9, 14)},
        {'id': 3, 'location': 3, 'demand': 3.0, 'time_window': (10, 16)},
        {'id': 4, 'location': 4, 'demand': 6.0, 'time_window': (11, 15)},
        {'id': 5, 'location': 5, 'demand': 4.0, 'time_window': (13, 17)}
    ]
    
    vehicles = [
        {'id': 'V001', 'capacity': 15.0},
        {'id': 'V002', 'capacity': 15.0},
        {'id': 'V003', 'capacity': 15.0}
    ]
    
    vrp_result = system.optimize_vehicle_routes(orders, vehicles)
    
    print(f"总距离: {vrp_result['total_distance']:.2f} km")
    print(f"使用车辆数: {vrp_result['num_vehicles_used']}")
    print(f"优化时间: {vrp_result['planning_time']:.2f} 秒")
    
    # 可视化
    routes_to_visualize = []
    for assignment in vrp_result['assignments']:
        routes_to_visualize.append(assignment['route'])
    
    system.visualize_routes(routes_to_visualize, "车辆路径优化结果")
    
    # 性能报告
    print("\n--- 系统性能报告 ---")
    metrics = system.get_performance_metrics()
    for key, value in metrics.items():
        if isinstance(value, float):
            print(f"{key}: {value:.4f}")
        else:
            print(f"{key}: {value}")

第六章:实战案例与评估指标

6.1 电商物流配送案例

python 复制代码
class ECommerceLogisticsCaseStudy:
    """
    电商物流配送案例研究
    """
    
    def __init__(self):
        self.scenarios = {
            'same_day_delivery': {
                'time_constraint': 4,  # 4小时内送达
                'priority': 'time',
                'algorithm': 'VRPTW'
            },
            'standard_delivery': {
                'time_constraint': 24,  # 24小时内送达
                'priority': 'cost',
                'algorithm': 'GeneticAlgorithm'
            },
            'bulk_delivery': {
                'time_constraint': 48,  # 48小时内送达
                'priority': 'vehicle_utilization',
                'algorithm': 'ClusteringFirst'
            }
        }
    
    def run_case_study(self, scenario: str, orders_data: List[dict]) -> dict:
        """
        运行案例研究
        """
        if scenario not in self.scenarios:
            raise ValueError(f"未知场景: {scenario}")
        
        config = self.scenarios[scenario]
        print(f"运行电商物流场景: {scenario}")
        print(f"配置: {config}")
        
        # 根据场景选择算法
        if config['algorithm'] == 'VRPTW':
            result = self.run_vrptw_solution(orders_data, config)
        elif config['algorithm'] == 'GeneticAlgorithm':
            result = self.run_genetic_algorithm_solution(orders_data, config)
        elif config['algorithm'] == 'ClusteringFirst':
            result = self.run_clustering_solution(orders_data, config)
        else:
            result = self.run_baseline_solution(orders_data, config)
        
        # 计算关键绩效指标
        kpis = self.calculate_kpis(result, config)
        
        return {
            'scenario': scenario,
            'config': config,
            'result': result,
            'kpis': kpis
        }
    
    def run_vrptw_solution(self, orders_data: List[dict], config: dict) -> dict:
        """
        运行VRPTW解决方案
        """
        # 这里使用前面实现的VRPTW求解器
        # 简化实现
        
        print("执行VRPTW算法...")
        
        # 模拟结果
        result = {
            'routes': [],
            'total_distance': 0.0,
            'total_time': 0.0,
            'vehicle_count': 0,
            'constraint_violations': 0
        }
        
        # 这里应该调用实际的VRPTW求解器
        # result = vrptw_solver.solve(orders_data, config)
        
        return result
    
    def calculate_kpis(self, result: dict, config: dict) -> dict:
        """
        计算关键绩效指标
        """
        kpis = {
            'cost_efficiency': 0.0,
            'time_efficiency': 0.0,
            'resource_utilization': 0.0,
            'customer_satisfaction': 0.0,
            'overall_score': 0.0
        }
        
        # 成本效率(距离越短越好)
        if result['total_distance'] > 0:
            kpis['cost_efficiency'] = 1000 / result['total_distance']
        
        # 时间效率(时间越短越好)
        if result['total_time'] > 0:
            kpis['time_efficiency'] = 100 / result['total_time']
        
        # 资源利用率(车辆使用越少越好)
        if result['vehicle_count'] > 0:
            kpis['resource_utilization'] = 50 / result['vehicle_count']
        
        # 客户满意度(约束违反越少越好)
        if result['constraint_violations'] == 0:
            kpis['customer_satisfaction'] = 100
        else:
            kpis['customer_satisfaction'] = max(0, 100 - result['constraint_violations'] * 10)
        
        # 综合评分(根据场景优先级加权)
        weights = self.get_kpi_weights(config['priority'])
        
        kpis['overall_score'] = (
            weights['cost'] * kpis['cost_efficiency'] +
            weights['time'] * kpis['time_efficiency'] +
            weights['resource'] * kpis['resource_utilization'] +
            weights['satisfaction'] * kpis['customer_satisfaction']
        ) / sum(weights.values())
        
        return kpis
    
    def get_kpi_weights(self, priority: str) -> dict:
        """
        根据优先级获取KPI权重
        """
        weights = {
            'cost': 0.25,
            'time': 0.25,
            'resource': 0.25,
            'satisfaction': 0.25
        }
        
        if priority == 'time':
            weights['time'] = 0.4
            weights['cost'] = 0.2
            weights['resource'] = 0.2
            weights['satisfaction'] = 0.2
        elif priority == 'cost':
            weights['cost'] = 0.4
            weights['time'] = 0.2
            weights['resource'] = 0.2
            weights['satisfaction'] = 0.2
        elif priority == 'vehicle_utilization':
            weights['resource'] = 0.4
            weights['cost'] = 0.3
            weights['time'] = 0.2
            weights['satisfaction'] = 0.1
        
        return weights
    
    def compare_scenarios(self, orders_data: List[dict]) -> dict:
        """
        比较不同场景的性能
        """
        comparison = {}
        
        for scenario in self.scenarios:
            print(f"\n{'='*50}")
            print(f"测试场景: {scenario}")
            print(f"{'='*50}")
            
            case_result = self.run_case_study(scenario, orders_data)
            comparison[scenario] = case_result['kpis']
            
            # 打印结果
            print(f"KPI指标:")
            for kpi, value in case_result['kpis'].items():
                print(f"  {kpi}: {value:.2f}")
        
        return comparison
    
    def visualize_comparison(self, comparison: dict):
        """
        可视化场景比较
        """
        scenarios = list(comparison.keys())
        kpi_names = ['cost_efficiency', 'time_efficiency', 
                    'resource_utilization', 'customer_satisfaction', 'overall_score']
        
        # 创建子图
        fig, axes = plt.subplots(2, 3, figsize=(15, 10))
        axes = axes.flatten()
        
        for i, kpi in enumerate(kpi_names):
            ax = axes[i]
            
            # 提取数据
            values = [comparison[scenario][kpi] for scenario in scenarios]
            
            # 创建柱状图
            bars = ax.bar(scenarios, values, color=['red', 'blue', 'green'])
            
            # 添加数值标签
            for bar, value in zip(bars, values):
                height = bar.get_height()
                ax.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                       f'{value:.2f}', ha='center', va='bottom')
            
            ax.set_title(kpi.replace('_', ' ').title())
            ax.set_ylabel('Score')
            ax.set_ylim(0, max(values) * 1.2 if values else 1.0)
            ax.grid(True, alpha=0.3, axis='y')
        
        # 隐藏多余的子图
        if len(kpi_names) < len(axes):
            for i in range(len(kpi_names), len(axes)):
                axes[i].axis('off')
        
        plt.suptitle('电商物流场景性能比较', fontsize=16, fontweight='bold')
        plt.tight_layout()
        plt.show()

# 使用示例
if __name__ == "__main__":
    # 创建案例研究
    case_study = ECommerceLogisticsCaseStudy()
    
    # 生成模拟订单数据
    np.random.seed(42)
    num_orders = 20
    
    orders_data = []
    for i in range(num_orders):
        order = {
            'id': i + 1,
            'location': np.random.randint(1, 100),  # 随机位置
            'demand': np.random.uniform(1, 10),  # 随机需求
            'priority': np.random.choice(['high', 'medium', 'low']),
            'time_window': (
                np.random.uniform(8, 18),  # 最早时间
                np.random.uniform(10, 20)   # 最晚时间
            )
        }
        orders_data.append(order)
    
    print(f"生成 {len(orders_data)} 个模拟订单")
    
    # 运行案例比较
    comparison = case_study.compare_scenarios(orders_data)
    
    # 可视化比较结果
    case_study.visualize_comparison(comparison)
    
    # 总结
    print("\n" + "="*60)
    print("电商物流路径规划案例研究总结")
    print("="*60)
    
    best_scenario = None
    best_score = -1
    
    for scenario, kpis in comparison.items():
        score = kpis['overall_score']
        print(f"\n{scenario}:")
        print(f"  综合评分: {score:.2f}")
        print(f"  成本效率: {kpis['cost_efficiency']:.2f}")
        print(f"  时间效率: {kpis['time_efficiency']:.2f}")
        print(f"  资源利用率: {kpis['resource_utilization']:.2f}")
        print(f"  客户满意度: {kpis['customer_satisfaction']:.2f}")
        
        if score > best_score:
            best_score = score
            best_scenario = scenario
    
    print(f"\n最佳场景: {best_scenario} (评分: {best_score:.2f})")

6.2 算法性能评估指标

python 复制代码
class AlgorithmEvaluator:
    """
    路径规划算法性能评估器
    """
    
    def __init__(self):
        self.metrics = {
            'computation_time': [],
            'solution_quality': [],
            'memory_usage': [],
            'scalability': [],
            'robustness': []
        }
    
    def evaluate_algorithm(self, algorithm_name: str, algorithm_func: Callable,
                          test_cases: List[dict]) -> dict:
        """
        评估算法性能
        """
        print(f"评估算法: {algorithm_name}")
        print(f"测试用例数: {len(test_cases)}")
        
        results = {
            'algorithm': algorithm_name,
            'test_cases': [],
            'summary': {}
        }
        
        for i, test_case in enumerate(test_cases):
            print(f"\n测试用例 {i+1}/{len(test_cases)}")
            print(f"  规模: {test_case['size']}")
            print(f"  复杂度: {test_case['complexity']}")
            
            # 运行算法
            case_result = self.run_single_test(algorithm_func, test_case)
            results['test_cases'].append(case_result)
            
            # 收集指标
            self.metrics['computation_time'].append(case_result['computation_time'])
            self.metrics['solution_quality'].append(case_result['solution_quality'])
            
            print(f"  计算时间: {case_result['computation_time']:.4f}秒")
            print(f"  解质量: {case_result['solution_quality']:.4f}")
        
        # 计算统计摘要
        results['summary'] = self.calculate_summary_statistics()
        
        return results
    
    def run_single_test(self, algorithm_func: Callable, test_case: dict) -> dict:
        """
        运行单个测试用例
        """
        start_time = time.time()
        
        # 运行算法
        try:
            solution = algorithm_func(test_case['data'])
            success = True
        except Exception as e:
            print(f"  算法执行失败: {e}")
            solution = None
            success = False
        
        computation_time = time.time() - start_time
        
        # 评估解质量
        if success and solution:
            solution_quality = self.evaluate_solution_quality(solution, test_case)
        else:
            solution_quality = 0.0
        
        # 测量内存使用(简化)
        memory_usage = self.estimate_memory_usage()
        
        return {
            'success': success,
            'computation_time': computation_time,
            'solution_quality': solution_quality,
            'memory_usage': memory_usage,
            'test_case': test_case
        }
    
    def evaluate_solution_quality(self, solution: dict, test_case: dict) -> float:
        """
        评估解质量
        """
        quality = 0.0
        
        # 距离优化(越短越好)
        if 'distance' in solution:
            max_possible = test_case.get('max_distance', 1000)
            quality += (max_possible - min(solution['distance'], max_possible)) / max_possible
        
        # 时间优化(越短越好)
        if 'time' in solution:
            max_possible = test_case.get('max_time', 24)
            quality += (max_possible - min(solution['time'], max_possible)) / max_possible
        
        # 资源使用(越少越好)
        if 'resources_used' in solution:
            max_resources = test_case.get('max_resources', 10)
            quality += (max_resources - solution['resources_used']) / max_resources
        
        # 约束满足(完全满足=1.0)
        if 'constraints_satisfied' in solution:
            quality += solution['constraints_satisfied']
        
        # 归一化到0-1范围
        quality = min(1.0, max(0.0, quality / 4.0))
        
        return quality
    
    def estimate_memory_usage(self) -> float:
        """
        估计内存使用(MB)
        """
        # 简化实现
        import psutil
        process = psutil.Process()
        memory_info = process.memory_info()
        return memory_info.rss / (1024 * 1024)  # 转换为MB
    
    def calculate_summary_statistics(self) -> dict:
        """
        计算统计摘要
        """
        summary = {}
        
        for metric_name, values in self.metrics.items():
            if values:
                summary[metric_name] = {
                    'mean': np.mean(values),
                    'std': np.std(values),
                    'min': np.min(values),
                    'max': np.max(values),
                    'median': np.median(values)
                }
            else:
                summary[metric_name] = None
        
        return summary
    
    def compare_algorithms(self, algorithms: Dict[str, Callable], 
                          test_cases: List[dict]) -> dict:
        """
        比较多个算法
        """
        comparison = {}
        
        for algo_name, algo_func in algorithms.items():
            print(f"\n{'='*60}")
            print(f"评估算法: {algo_name}")
            print(f"{'='*60}")
            
            results = self.evaluate_algorithm(algo_name, algo_func, test_cases)
            comparison[algo_name] = results
        
        return comparison
    
    def visualize_comparison(self, comparison: dict):
        """
        可视化算法比较
        """
        algorithms = list(comparison.keys())
        
        # 创建图形
        fig, axes = plt.subplots(2, 3, figsize=(15, 10))
        axes = axes.flatten()
        
        metrics_to_plot = ['computation_time', 'solution_quality', 
                          'memory_usage', 'scalability', 'robustness']
        
        for i, metric in enumerate(metrics_to_plot):
            if i >= len(axes):
                break
            
            ax = axes[i]
            
            # 提取数据
            data = []
            labels = []
            
            for algo in algorithms:
                summary = comparison[algo]['summary'].get(metric)
                if summary and summary['mean'] is not None:
                    data.append(summary['mean'])
                    labels.append(algo)
            
            if data:
                # 创建柱状图
                bars = ax.bar(range(len(data)), data, color=plt.cm.Set3(range(len(data))))
                
                # 添加误差条
                for j, algo in enumerate(algorithms):
                    summary = comparison[algo]['summary'].get(metric)
                    if summary and summary['std'] is not None:
                        ax.errorbar(j, data[j], yerr=summary['std'], 
                                   fmt='none', color='black', capsize=5)
                
                ax.set_xticks(range(len(data)))
                ax.set_xticklabels(labels, rotation=45, ha='right')
                ax.set_title(metric.replace('_', ' ').title())
                ax.set_ylabel('Value')
                ax.grid(True, alpha=0.3, axis='y')
            
            else:
                ax.text(0.5, 0.5, f'No data for {metric}', 
                       ha='center', va='center', transform=ax.transAxes)
                ax.set_title(metric.replace('_', ' ').title())
        
        # 隐藏多余的子图
        for i in range(len(metrics_to_plot), len(axes)):
            axes[i].axis('off')
        
        plt.suptitle('路径规划算法性能比较', fontsize=16, fontweight='bold')
        plt.tight_layout()
        plt.show()
        
        # 综合评分雷达图
        self.plot_radar_chart(comparison)
    
    def plot_radar_chart(self, comparison: dict):
        """
        绘制综合评分雷达图
        """
        algorithms = list(comparison.keys())
        metrics = ['computation_time', 'solution_quality', 'memory_usage']
        
        # 标准化数据(值越大越好)
        normalized_data = {}
        
        for algo in algorithms:
            summary = comparison[algo]['summary']
            algo_data = []
            
            for metric in metrics:
                if summary.get(metric) and summary[metric]['mean'] is not None:
                    value = summary[metric]['mean']
                    
                    # 对于计算时间和内存使用,值越小越好,所以取倒数
                    if metric in ['computation_time', 'memory_usage']:
                        if value > 0:
                            normalized = 1.0 / value
                        else:
                            normalized = 0.0
                    else:
                        normalized = min(1.0, max(0.0, value))
                    
                    algo_data.append(normalized)
                else:
                    algo_data.append(0.0)
            
            normalized_data[algo] = algo_data
        
        # 创建雷达图
        angles = np.linspace(0, 2 * np.pi, len(metrics), endpoint=False).tolist()
        angles += angles[:1]  # 闭合图形
        
        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(projection='polar'))
        
        colors = plt.cm.tab10(np.linspace(0, 1, len(algorithms)))
        
        for i, (algo, data) in enumerate(normalized_data.items()):
            # 闭合数据
            closed_data = data + data[:1]
            
            # 绘制雷达图
            ax.plot(angles, closed_data, 'o-', linewidth=2, label=algo, color=colors[i])
            ax.fill(angles, closed_data, alpha=0.1, color=colors[i])
        
        # 设置标签
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels([m.replace('_', '\n').title() for m in metrics])
        ax.set_ylim(0, 1.0)
        ax.set_title('算法综合性能雷达图', fontsize=14, fontweight='bold')
        ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
        ax.grid(True)
        
        plt.tight_layout()
        plt.show()

# 使用示例
if __name__ == "__main__":
    # 创建评估器
    evaluator = AlgorithmEvaluator()
    
    # 定义测试算法
    def dijkstra_algorithm(test_data):
        """Dijkstra算法实现"""
        planner = DijkstraPathPlanner(test_data['graph'])
        path, distance = planner.find_shortest_path(
            test_data['start'], 
            test_data['end']
        )
        return {'path': path, 'distance': distance}
    
    def astar_algorithm(test_data):
        """A*算法实现"""
        planner = AStarPathPlanner(
            test_data['graph'],
            test_data['coordinates']
        )
        path, cost = planner.find_path(
            test_data['start'], 
            test_data['end']
        )
        return {'path': path, 'distance': cost}
    
    def genetic_algorithm(test_data):
        """遗传算法实现(简化)"""
        # 这里使用前面实现的遗传算法
        ga_solver = GeneticAlgorithmVRP(
            distance_matrix=test_data['distance_matrix'],
            demands=test_data['demands'],
            vehicle_capacity=test_data['vehicle_capacity']
        )
        solution, fitness = ga_solver.optimize(generations=50)
        return {'solution': solution, 'fitness': fitness}
    
    # 准备测试用例
    test_cases = []
    
    for size in [10, 20, 50, 100]:
        # 生成随机图
        graph = {}
        coordinates = {}
        
        for i in range(size):
            graph[i] = []
            coordinates[i] = (random.random() * 100, random.random() * 100)
            
            # 随机连接一些边
            for j in range(size):
                if i != j and random.random() < 0.1:
                    weight = random.random() * 10
                    graph[i].append((j, weight))
        
        test_case = {
            'size': size,
            'complexity': 'medium',
            'data': {
                'graph': graph,
                'coordinates': coordinates,
                'start': 0,
                'end': size - 1,
                'distance_matrix': np.random.rand(size, size) * 10,
                'demands': np.random.rand(size) * 5,
                'vehicle_capacity': 20.0,
                'max_distance': size * 10,
                'max_time': size * 2
            }
        }
        
        test_cases.append(test_case)
    
    print(f"准备 {len(test_cases)} 个测试用例")
    
    # 定义要比较的算法
    algorithms = {
        'Dijkstra': dijkstra_algorithm,
        'A*': astar_algorithm,
        'GeneticAlgorithm': genetic_algorithm
    }
    
    # 比较算法
    comparison = evaluator.compare_algorithms(algorithms, test_cases)
    
    # 可视化比较结果
    evaluator.visualize_comparison(comparison)
    
    # 输出详细结果
    print("\n" + "="*60)
    print("算法性能评估详细结果")
    print("="*60)
    
    for algo_name, results in comparison.items():
        print(f"\n{algo_name}:")
        print(f"  成功测试用例: {sum(1 for tc in results['test_cases'] if tc['success'])}/{len(results['test_cases'])}")
        
        summary = results['summary']
        if summary.get('computation_time'):
            comp_time = summary['computation_time']
            print(f"  平均计算时间: {comp_time['mean']:.4f}±{comp_time['std']:.4f}秒")
        
        if summary.get('solution_quality'):
            quality = summary['solution_quality']
            print(f"  平均解质量: {quality['mean']:.4f}±{quality['std']:.4f}")
    
    # 确定最佳算法
    best_algo = None
    best_score = -1
    
    for algo_name, results in comparison.items():
        summary = results['summary']
        
        # 计算综合评分
        if summary.get('computation_time') and summary.get('solution_quality'):
            # 时间越短越好,质量越高越好
            time_score = 1.0 / (summary['computation_time']['mean'] + 1e-6)
            quality_score = summary['solution_quality']['mean']
            
            # 加权综合评分
            overall_score = 0.6 * quality_score + 0.4 * time_score
            
            if overall_score > best_score:
                best_score = overall_score
                best_algo = algo_name
    
    print(f"\n综合最佳算法: {best_algo} (评分: {best_score:.4f})")

总结与资源

核心算法总结

算法类别 适用场景 优点 缺点 时间复杂度
Dijkstra 静态环境最短路径 保证找到最优解,实现简单 搜索效率低,不适合大规模图 O(V²) 或 O(E log V)
A* 已知目标点的路径规划 搜索效率高,启发式引导 需要良好的启发式函数 O(b^d)
D* 动态环境路径规划 支持实时重规划,效率高 实现复杂,需要维护状态 O(n log n)
RRT 高维空间路径规划 适合复杂约束,概率完备性 解不一定最优,随机性大 O(n log n)
遗传算法 组合优化问题(VRP) 全局搜索能力强,并行性好 参数敏感,可能早熟收敛 O(p·g·n)
蚁群算法 旅行商类问题 正反馈机制,鲁棒性好 收敛速度慢,参数调优复杂 O(nc·m·n²)

优化策略对比

策略 适用问题 核心思想 实现难度 效果
局部搜索 路径优化 在邻域内寻找更优解 简单 中等
模拟退火 全局优化 概率性接受劣解跳出局部最优 中等 良好
禁忌搜索 组合优化 记录搜索历史避免循环 中等 良好
大邻域搜索 复杂VRP 破坏-重建策略 复杂 优秀

学习资源推荐

  1. 经典书籍

    • 《算法导论》 - 基础算法理论
    • 《车辆路径问题:模型与算法》 - VRP专题
    • 《智能优化算法及其应用》 - 优化算法合集
  2. 在线课程

    • Coursera: Discrete Optimization
    • 中国大学MOOC: 智能优化算法
    • Udemy: Advanced Algorithms and Data Structures
  3. 开源项目

  4. 学术资源

    • IEEE Transactions on Intelligent Transportation Systems
    • Transportation Science 期刊
    • 中国公路学报

实践建议

  1. 问题分析阶段

    • 明确业务约束和优化目标
    • 收集准确的基础数据
    • 确定性能评估指标
  2. 算法选择阶段

    • 从小规模问题开始验证
    • 结合多种算法优势
    • 考虑实时性要求
  3. 系统实现阶段

    • 模块化设计,便于替换算法
    • 实现缓存机制提高性能
    • 添加可视化调试工具
  4. 优化改进阶段

    • 基于实际数据调优参数
    • 考虑分布式计算扩展
    • 集成机器学习预测

未来发展方向

  1. 智能学习型规划:结合强化学习,让系统从历史数据中学习优化策略
  2. 多式联运优化:考虑公路、铁路、航空等多种运输方式的协同
  3. 绿色物流优化:加入碳排放等环保指标,实现可持续发展
  4. 实时自适应规划:基于物联网数据的实时动态调整
  5. 数字孪生仿真:在虚拟环境中测试优化策略后再实施
相关推荐
json{shen:"jing"}2 小时前
字符串中的第一个唯一字符
算法·leetcode·职场和发展
追随者永远是胜利者2 小时前
(LeetCode-Hot100)15. 三数之和
java·算法·leetcode·职场和发展·go
BlockWay3 小时前
西甲赛程搬进平台:WEEX以竞猜开启区域合作落地
大数据·人工智能·算法·安全
im_AMBER5 小时前
Leetcode 121 翻转二叉树 | 二叉树中的最大路径和
数据结构·学习·算法·leetcode
mit6.8245 小时前
二分+贪心
算法
programhelp_6 小时前
特斯拉 MLE 超详细面经 + 避坑
数据结构·人工智能·算法·面试·职场和发展
越甲八千7 小时前
深入了解迭代器erase()之后的失效逻辑
算法
躺柒7 小时前
读人工智能全球格局:未来趋势与中国位势06人类的未来(下)
大数据·人工智能·算法·ai·智能
L_Aria7 小时前
6421. 【NOIP2019模拟11.11】匹配
c++·算法·动态规划