文章目录
-
- 第一章:智能物流路径规划系统概述
-
- [1.1 物流路径规划的核心问题](#1.1 物流路径规划的核心问题)
- [1.2 系统架构设计](#1.2 系统架构设计)
- [1.3 关键技术指标](#1.3 关键技术指标)
- 第二章:基础路径规划算法原理与实现
-
- [2.1 Dijkstra算法:基础最短路径算法](#2.1 Dijkstra算法:基础最短路径算法)
- [2.2 A*算法:启发式搜索优化](#2.2 A*算法:启发式搜索优化)
- [2.3 D*算法:动态环境路径规划](#2.3 D*算法:动态环境路径规划)
- [2.4 RRT(快速探索随机树)算法](#2.4 RRT(快速探索随机树)算法)
- 第三章:高级路径优化策略
-
- [3.1 遗传算法在车辆路径问题中的应用](#3.1 遗传算法在车辆路径问题中的应用)
- [3.2 蚁群算法优化](#3.2 蚁群算法优化)
- 第四章:多约束条件下的路径规划
-
- [4.1 带时间窗的车辆路径问题(VRPTW)](#4.1 带时间窗的车辆路径问题(VRPTW))
- 第五章:完整系统实现与性能优化
-
- [5.1 系统架构设计](#5.1 系统架构设计)
- 第六章:实战案例与评估指标
-
- [6.1 电商物流配送案例](#6.1 电商物流配送案例)
- [6.2 算法性能评估指标](#6.2 算法性能评估指标)
- 总结与资源
第一章:智能物流路径规划系统概述
1.1 物流路径规划的核心问题
智能物流路径规划系统是现代物流管理的核心技术,主要解决以下核心问题:
- 最短路径问题:在路网中找到两点间的最短行驶距离或时间
- 车辆路径问题:为多辆配送车辆规划最优配送路线
- 旅行商问题:单一车辆访问多个点的最优顺序问题
- 带时间窗的路径规划:考虑客户时间约束的配送路线规划
- 动态路径规划:实时响应交通状况变化的路线调整
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 | 破坏-重建策略 | 复杂 | 优秀 |
学习资源推荐
-
经典书籍:
- 《算法导论》 - 基础算法理论
- 《车辆路径问题:模型与算法》 - VRP专题
- 《智能优化算法及其应用》 - 优化算法合集
-
在线课程:
- Coursera: Discrete Optimization
- 中国大学MOOC: 智能优化算法
- Udemy: Advanced Algorithms and Data Structures
-
开源项目:
-
学术资源:
- IEEE Transactions on Intelligent Transportation Systems
- Transportation Science 期刊
- 中国公路学报
实践建议
-
问题分析阶段:
- 明确业务约束和优化目标
- 收集准确的基础数据
- 确定性能评估指标
-
算法选择阶段:
- 从小规模问题开始验证
- 结合多种算法优势
- 考虑实时性要求
-
系统实现阶段:
- 模块化设计,便于替换算法
- 实现缓存机制提高性能
- 添加可视化调试工具
-
优化改进阶段:
- 基于实际数据调优参数
- 考虑分布式计算扩展
- 集成机器学习预测
未来发展方向
- 智能学习型规划:结合强化学习,让系统从历史数据中学习优化策略
- 多式联运优化:考虑公路、铁路、航空等多种运输方式的协同
- 绿色物流优化:加入碳排放等环保指标,实现可持续发展
- 实时自适应规划:基于物联网数据的实时动态调整
- 数字孪生仿真:在虚拟环境中测试优化策略后再实施