import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
import os
# ==================== 遗传算法参数配置 ====================
POP_SIZE = 200 # 种群规模
MAX_GEN = 500 # 最大迭代次数
CX_RATE = 0.85 # 交叉概率
MUT_RATE = 0.15 # 变异概率
ELITE_RATE = 0.1 # 精英保留比例
# ==================== 数据准备与预处理 ====================
def load_data(file_path):
"""加载并预处理数据"""
df = pd.read_excel(file_path, skiprows=1, usecols="A:D")
df.columns = ['节点', 'x', 'y', '需求']
df['需求'] = pd.to_numeric(df['需求'], errors='coerce').fillna(0)
coordinates = df[['x', 'y']].values
demands = df['需求'].values
return coordinates, demands
# ==================== 核心算法实现 ====================
class GeneticVRP:
def __init__(self, coords, demands, capacity, pop_size):
self.coords = coords
self.demands = demands
self.capacity = capacity
self.pop_size = pop_size
self.n = len(coords)
self.dist_matrix = self.calc_distance_matrix()
def calc_distance_matrix(self):
"""计算距离矩阵"""
dist = np.zeros((self.n, self.n))
for i in range(self.n):
for j in range(self.n):
dist[i][j] = np.linalg.norm(self.coords[i] - self.coords[j])
return np.round(dist, 2)
def init_population(self):
"""生成初始种群"""
population = []
for _ in range(self.pop_size):
# 随机生成满足载重约束的路径
unvisited = list(range(1, self.n))
routes = []
while unvisited:
route = [0] # 起点为处理厂
load = 0
while unvisited and (load + self.demands[unvisited[0]] <= self.capacity):
next_node = np.random.choice(unvisited)
if load + self.demands[next_node] > self.capacity:
break
route.append(next_node)
load += self.demands[next_node]
unvisited.remove(next_node)
route.append(0) # 返回处理厂
routes.append(route)
population.append(routes)
return population
def fitness(self, individual):
"""计算适应度(总距离的倒数)"""
total_dist = 0
for route in individual:
for i in range(len(route)-1):
total_dist += self.dist_matrix[route[i]][route[i+1]]
return 1 / (total_dist + 1e-6) # 防止除零错误
def selection(self, population, fitnesses):
"""锦标赛选择"""
selected = []
tournament_size = 5
for _ in range(len(population)):
candidates = np.random.choice(len(population), tournament_size, replace=False)
best_idx = candidates[np.argmax([fitnesses[c] for c in candidates])]
selected.append(population[best_idx])
return selected
def cx_partially_matched(self, ind1, ind2):
"""部分匹配交叉"""
# 实现交叉操作,保留有效路径结构
# ...(具体实现代码较长,此处省略)
def mut_inversion(self, individual):
"""路径倒置变异"""
# 随机选择一段路径进行倒置
# ...(具体实现代码较长,此处省略)
def evolve(self, population):
"""进化一代"""
# 计算适应度
fitnesses = [self.fitness(ind) for ind in population]
# 精英保留
elite_size = int(self.pop_size * ELITE_RATE)
elite = sorted(zip(population, fitnesses), key=lambda x: x[1], reverse=True)[:elite_size]
elite = [e[0] for e in elite]
# 选择
selected = self.selection(population, fitnesses)
# 交叉
offspring = []
for i in range(0, len(selected), 2):
if np.random.rand() < CX_RATE:
child1, child2 = self.cx_partially_matched(selected[i], selected[i+1])
offspring.extend([child1, child2])
# 变异
for i in range(len(offspring)):
if np.random.rand() < MUT_RATE:
offspring[i] = self.mut_inversion(offspring[i])
# 生成新种群
new_pop = elite + offspring
while len(new_pop) < self.pop_size:
new_pop.append(random.choice(population))
return new_pop[:self.pop_size]
# ==================== 结果可视化 ====================
def plot_solution(routes, coords):
plt.figure(figsize=(12, 10))
colors = cm.get_cmap('tab20', len(routes))
# 绘制所有节点
plt.scatter(coords[1:,0], coords[1:,1], c='black', s=50, label='收集点')
plt.scatter(coords[0,0], coords[0,1], c='red', marker='*', s=300, label='处理厂')
# 绘制路径
for i, route in enumerate(routes):
path = coords[route]
plt.plot(path[:,0], path[:,1], lw=2, color=colors(i),
label=f'车辆{i+1} ({len(route)-2}个点)')
plt.arrow(path[-2,0], path[-2,1],
path[-1,0]-path[-2,0], path[-1,1]-path[-2,1],
color=colors(i), head_width=0.5, length_includes_head=True)
plt.title('优化后的垃圾运输路径', fontsize=14)
plt.xlabel('X 坐标 (km)', fontsize=12)
plt.ylabel('Y 坐标 (km)', fontsize=12)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
# ==================== 主程序执行 ====================
if __name__ == "__main__":
# 数据加载
file_path = "E:\sxjm\附件1(1).xlsx"
coordinates, demands = load_data(file_path)
capacity = 5.0
# 初始化算法
ga = GeneticVRP(coordinates, demands, capacity, POP_SIZE)
population = ga.init_population()
# 进化过程
best_fitness = []
for gen in range(MAX_GEN):
population = ga.evolve(population)
current_best = max([ga.fitness(ind) for ind in population])
best_fitness.append(1/current_best - 1e-6)
print(f"Generation {gen+1}/{MAX_GEN} | 当前最优距离: {best_fitness[-1]:.2f} km")
# 提取最优解
best_idx = np.argmin([sum(ga.calc_total_distance(ind)) for ind in population])
best_solution = population[best_idx]
# 结果展示
total_dist = sum(ga.calc_total_distance(best_solution))
print(f"\n优化结果:")
print(f"总使用车辆数:{len(best_solution)}")
print(f"总行驶距离:{total_dist:.2f} km")
# 可视化
plot_solution(best_solution, coordinates)