仍然是参考https://blog.csdn.net/baiyuxuan123123/article/details/114818224这个文章,编码做了一下这个题:
有一配送中心,负责将货物配送到指定的各个配送点。每个配送点有一定的货物需求量,用货物重量表示。
配送中心有若干辆车,每辆车有一定的载重量和里程限制,车的载重和行驶里程不可超过指定的值。
一辆车可负责一个或多个点的配送任务,且每个配送点只被服务一次。
在某一时刻,所有负责配送的车同时从配送中心出发,分别完成各自的配送任务后,再回到配送中心。
根据以上条件,设计一个最优配送方案。对于每个方案,应给出每辆车负责的配送点及其先后顺序。
为衡量方案之间的优劣,我们给出如下三个指标:
配送总时间t:从配送开始 到最后一辆车返回物流中心所经历的时间
车辆总里程s:所有配送车辆的里程之和
车辆总数n:用于配送的车辆数量
在实际应用中,我们为这三个指标分别分配一个权重 wt ws 和 wn 用如下公式作为每个方案的得分:得分越高,方案越优。
score = − ( wt ⋅ t + ws ⋅ s + wn ⋅ n )
import random
import pickle
from collections import namedtuple
import numpy as np
from scipy.spatial.distance import pdist, squareform
import matplotlib.pyplot as plt
# ***** begin 配置信息 *****
# **** 题目数据配置
generate_new_flag = True
max_car_no = 10
min_car_no = 8 # 如果car_no设置得较小,可能会鉴权失败多次,效率差 不能设置得大于 cargo_site_total
cargo_site_total = 20
site_location_range = tuple(range(-100, 101, 5))
car_carrying_range = tuple(range(180, 221, 10))
car_speed_range = tuple(range(20, 41, 10))
move_cargo_second = 2 # 简化处理的每次装卸货时间, 也可以使用与货物重量相关的变量
max_cargo_weight = 100
max_car_distance = 1200
time_weight = 0.4
distance_weight = 0.3
cargo_no_weight = 1 - time_weight - distance_weight
# **** 算法配置
max_iter = 1000
algorithm_GA = False
algorithm_ACO = True
# *** GA配置
population_size = 100
mutate_max_try_times = 20
select_ratio = 0.5
# *** aco 配置
ant_no = 10
pheromone_factor_alpha = 1 # 信息素启发式因子
visible_factor_beta = 2 # 能见度启发式因子
volatil_factor = 0.5 # 信息素挥发速度
pheromone_cons = 100 # 信息素强度
# **** 画图配置
plot_flag = False # windows下运行 可设为True
# ***** end 配置信息 *****
# 其他定义
cargo_site_info = namedtuple("cargo_site_info", ("site_location_x", "site_location_y", "cargo_weight"))
car_info = namedtuple("car_info", ("speed", "volume"))
# 正常情况 应该把Utils写成一个文件或文件夹 而不是一个类..
class Utils:
@staticmethod
def pickle_dump(data, write_file):
pickle_file = open(write_file, 'wb')
pickle.dump(data, pickle_file)
pickle_file.close()
return None
@staticmethod
def pickle_load(read_file):
pickle_file = open(read_file, 'rb')
result = pickle.load(pickle_file)
pickle_file.close()
return result
class QuestionDataHandle:
def __init__(self):
pass
def get_data(self, generate_new=False, pick_file='vrp_question.pick'):
if not generate_new:
try:
print("will get data by file!")
# 目前的实现 配置信息不能在导出后有变化。 如需优化 需要将题目数据配置信息 同时导出导入
return Utils.pickle_load(pick_file)
except Exception as e:
print("!! Attention !! can not load from vrp_question.pick. will generate new! \n")
# 报错后,继续用新生成的数据 当然 这里也可以报错后 退出处理
return self.generate_data_process(pick_file)
def generate_data_process(self, pick_file):
cargo_sites, cargo_site_info_dict, car_info_dict = self.generate_data()
Utils.pickle_dump((cargo_sites, cargo_site_info_dict, car_info_dict), pick_file)
return cargo_sites, cargo_site_info_dict, car_info_dict
def generate_data(self):
cargo_sites = list(range(1, cargo_site_total + 1)) # cargo_site 从1开始, 0留给这里唯一的配送中心
car_info_dict = {car_no: car_info(random.choice(car_speed_range),
random.choice(car_carrying_range))
for car_no in range(1, max_car_no + 1)}
return cargo_sites, self.get_cargo_site_info(cargo_sites), car_info_dict
def get_cargo_site_info(self, cargo_sites):
while True:
cargo_site_info_dict = {site_no: cargo_site_info(random.choice(site_location_range),
random.choice(site_location_range),
random.randint(0, max_cargo_weight))
for site_no in cargo_sites}
# 补充起点和终点的site_location信息,计算距离时会用到。最后一个weight用不到
cargo_site_info_dict[0] = cargo_site_info(0, 0, 0)
# 偶尔有生成的货物点 xy坐标都一样的情况,此时重新再生成
site_location_list = [(info.site_location_x, info.site_location_y)
for info in cargo_site_info_dict.values()]
if len(set(site_location_list)) == len(site_location_list):
return cargo_site_info_dict
class VRPData:
def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict):
self.cargo_sites = cargo_sites
self.cargo_site_info_dict = cargo_site_info_dict
self.car_info_dict = car_info_dict
self.site_location = [(info.site_location_x, info.site_location_y)
for key, info in sorted(self.cargo_site_info_dict.items(), key=lambda x: x[0])]
def get_a_possible_try(self, cargo_site_list=None):
if not cargo_site_list:
cargo_site_list = random.sample(self.cargo_sites, car