仍然是参考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 = 1200time_weight = 0.4
distance_weight = 0.3
cargo_no_weight = 1 - time_weight - distance_weight# **** 算法配置
max_iter = 1000
algorithm_GA = False
algorithm_ACO = True
algorithm_ACO_and_alns = False# *** 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:@staticmethoddef pickle_dump(data, write_file):pickle_file = open(write_file, 'wb')pickle.dump(data, pickle_file)pickle_file.close()return None@staticmethoddef pickle_load(read_file):pickle_file = open(read_file, 'rb')result = pickle.load(pickle_file)pickle_file.close()return resultclass QuestionDataHandle:def __init__(self):passdef 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_dictdef 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_dictdef 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_dictclass VRPData:def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict):self.cargo_sites = cargo_sitesself.cargo_site_info_dict = cargo_site_info_dictself.car_info_dict = car_info_dictself.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, cargo_site_total)try_times = 0while True:car_list = random.sample(range(1, max_car_no + 1), random.randint(min_car_no, max_car_no))# 不生成在cargo_sites的第一位和最后一位   car_location 从1开始(非从0开始)car_location = random.sample(range(2, cargo_site_total - 1), len(car_list) - 1)car_location.append(cargo_site_total)  # 最后 一辆车car_location.sort()car_location2no = {location: car_no for location, car_no in zip(car_location, car_list)}# 其实不做强鉴权 或以一定概率 保持不合法的解 也是可以的,后面可能变异成 合法的解if self.cargo_site_and_car_location_authok(cargo_site_list, car_location, car_location2no):breaktry_times += 1if try_times >= 500:print("get_a_possible_try try times is %s:" % try_times)cargo_site_car_list, cargo_car_loc2carno = self.get_cargo_site_car_list(car_location, cargo_site_list, car_list)return cargo_site_car_list, cargo_car_loc2carnodef get_cargo_site_car_list(self, car_location, cargo_site_list, car_list):cargo_site_car_list = cargo_site_list.copy()# todo 效率for location in car_location[::-1]:cargo_site_car_list.insert(location, 0)cargo_car_loc2carno = self.get_cargo_car_loc2carno(cargo_site_car_list, car_list)return cargo_site_car_list, cargo_car_loc2carnodef get_cargo_car_loc2carno(self, cargo_site_car_list, car_list):ix = 0cargo_car_loc2carno = {}for location_ix, location in enumerate(cargo_site_car_list):if location == 0:cargo_car_loc2carno[location_ix] = car_list[ix]ix += 1return cargo_car_loc2carnodef cargo_site_and_car_location_authok(self, cargo_site_list, car_location, car_location2no):# 如果生成连续两个0  两辆车连在一起 后一辆未载重 放弃if (np.diff(np.array(car_location)) == 0).any():return False# 如果car_no较小,可能会鉴权失败多次,效率差last_index = 0for location in car_location:tmp_cargo_sites = cargo_site_list[last_index: location]if sum([self.cargo_site_info_dict[cargo_site_no].cargo_weight for cargo_site_no in tmp_cargo_sites]) > self.car_info_dict[car_location2no[location]].volume:return Falselast_index = locationreturn Truedef cargo_site_car_list_authok(self, cargo_site_car_list, cargo_car_loc2carno):last_index = 0for location_ix, location in enumerate(cargo_site_car_list):if location == 0:tmp_cargo_sites = cargo_site_car_list[last_index: location_ix]if sum([self.cargo_site_info_dict[cargo_site_no].cargo_weight for cargo_site_no in tmp_cargo_sites]) > self.car_info_dict[cargo_car_loc2carno[location_ix]].volume:# print("location_index", location_index, car_info_dict[car_ix + 1],  car_ix + 1,)return Falselast_index = location_ixreturn Truedef get_population_by_size(self, size=population_size):population_info = [self.get_a_possible_try() for _ in range(size)]return population_infoclass VRPPlot:def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict):self.data = VRPData(cargo_sites, cargo_site_info_dict, car_info_dict)@classmethoddef cp_from_ins(cls, vrp_data_ins):plt_ins = cls(vrp_data_ins.cargo_sites, vrp_data_ins.cargo_site_info_dict, vrp_data_ins.car_info_dict)return plt_insdef run(self, cargo_site_car_list):plot_data = self.get_plot_data(cargo_site_car_list)fig1 = plt.figure(1)for a_car_path in plot_data:self.plot_path(a_car_path)plt.draw()plt.pause(10)plt.close(fig1)def get_plot_data(self, cargo_site_car_list):plot_data = []a_car_path = []for x in cargo_site_car_list:if not x:plot_data.append([0] + a_car_path + [0])a_car_path = []else:a_car_path.append(x)return plot_datadef plot_path(self, path):x_list = []y_list = []for x in path:temp = self.data.site_location[x]x_list.append(temp[0])y_list.append(temp[1])plt.plot(x_list, y_list)class VrpHeuristic:def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict):self.data = VRPData(cargo_sites, cargo_site_info_dict, car_info_dict)self.distance_matrix = squareform(pdist(np.array(self.data.site_location)))def get_fitness_info(self, cargo_site_car_list, cargo_car_loc2carno):car_ix_consume_time, distances = self.calculate_fitness_info(cargo_site_car_list, cargo_car_loc2carno)return -(time_weight * max(car_ix_consume_time.values()) + distance_weight * sum(distances)+ cargo_no_weight * len(cargo_car_loc2carno))def calculate_fitness_info(self, cargo_site_car_list, cargo_car_loc2carno):distances = []car_ix_consume_time = {}    # car_ix 不是 car_no, 只为后面变异提供参考car_ix = 0last_site_no = 0   # 其实不会有0号site  这里是为了计算距离distance = 0for ix, x in enumerate(cargo_site_car_list):tmp_distance = self.distance_matrix[x][last_site_no]if x > 0:distance += tmp_distancelast_site_no = xelse:distances.append(distance)consume_time = (distance / self.data.car_info_dict[cargo_car_loc2carno[ix]].speed) + move_cargo_secondcar_ix += 1car_ix_consume_time[car_ix] = consume_timelast_site_no = 0distance = 0return car_ix_consume_time, distancesdef get_distance_by_path(self, path):distance = []last_index = -1for ix, site in enumerate(path):if ix != 0:distance.append(self.distance_matrix[last_index][site])last_index = sitereturn distanceclass GA(VrpHeuristic):def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict):super().__init__(cargo_sites, cargo_site_info_dict, car_info_dict)def __call__(self):population_info = self.data.get_population_by_size()for ix in range(max_iter):population_fitness_info = self.get_fitness_by_length(population_info)population_info = self.select_mutate_multiply(population_fitness_info)if ix % 10 == 0:self.print_middle_reslt(ix, population_info)self.print_final_result(population_info)def get_fitness_info(self, cargo_site_car_list, cargo_car_loc2carno):car_ix_consume_time, distances = self.calculate_fitness_info(cargo_site_car_list, cargo_car_loc2carno)return -(time_weight * max(car_ix_consume_time.values()) + distance_weight * sum(distances)+ cargo_no_weight * len(cargo_car_loc2carno)), car_ix_consume_timedef get_fitness_by_length(self, population_info):population_fitness_info = []for cargo_site_car_list, cargo_car_loc2carno in population_info:population_fitness_info.append((*self.get_fitness_info(cargo_site_car_list, cargo_car_loc2carno),cargo_site_car_list, cargo_car_loc2carno))return population_fitness_infodef cross_and_mutation_by_fitness(self, population_fitness_info):new_pop = []passdef select_mutate_multiply(self, population_fitness_info, select_ratio=select_ratio):new_population_info = []# selectpopulation_fitness_info.sort(key=lambda x: x[0], reverse=True)new_population_fitness_info = population_fitness_info[:int(len(population_fitness_info) * select_ratio + 1)]# 在select 后的基础上变异for fitness_score, car_ix_consume_time, cargo_site_car_list, cargo_car_loc2carno in new_population_fitness_info:new_population_info.append(self.mutate(cargo_site_car_list, cargo_car_loc2carno, car_ix_consume_time))# 繁殖新的一批new_population_info.extend([self.data.get_a_possible_try()for _ in range(int(len(population_fitness_info) * select_ratio))])return new_population_infodef mutate(self, cargo_site_car_list, cargo_car_loc2carno, car_ix_consume_time, max_try_times=mutate_max_try_times):try_times = 0while try_times <= max_try_times:# 这只是一种变异的方式 也可以根据fitness的各项指标 分别设计to_move_min_ix, to_move_max_ix, to_move_max_value = self.get_move_info(cargo_site_car_list, cargo_car_loc2carno, car_ix_consume_time)new_cargo_site_car_list, new_cargo_car_loc2carno = self.get_move_result(cargo_site_car_list, cargo_car_loc2carno, to_move_min_ix, to_move_max_ix, to_move_max_value)if self.data.cargo_site_car_list_authok(new_cargo_site_car_list, new_cargo_car_loc2carno):# print("mutate success. try times is %s:" % try_times)return new_cargo_site_car_list, new_cargo_car_loc2carnotry_times += 1# print("mutate fail after try times is %s:" % max_try_times)return cargo_site_car_list, cargo_car_loc2carnodef get_move_info(self, cargo_site_car_list, cargo_car_loc2carno, car_ix_consume_time):# 把耗时最长的车辆对应的货物点 移一个加到耗时最短的车辆对应的货物点sorted_car_time = sorted(car_ix_consume_time.items(), key=lambda x: x[1])min_ix = sorted_car_time[0][0]max_ix = sorted_car_time[-1][0]larger_range = list(cargo_car_loc2carno.keys())[max(max_ix - 2, 0): max_ix]smaller_range = list(cargo_car_loc2carno.keys())[max(min_ix - 2, 0): min_ix]to_move_min_ix = random.choice(list(range(smaller_range[0], smaller_range[1]))) if len(smaller_range) > 1 else smaller_range[0]to_move_max_ix = random.choice(list(range(larger_range[0] + 1, larger_range[1]))) if len(larger_range) > 1 else larger_range[0]to_move_max_value = cargo_site_car_list[to_move_max_ix]return to_move_min_ix, to_move_max_ix, to_move_max_valuedef get_move_result(self, cargo_site_car_list, cargo_car_loc2carno,to_move_min_ix, to_move_max_ix, to_move_max_value):new_cargo_site_car_list = []for location_ix, location in enumerate(cargo_site_car_list):if location_ix != to_move_max_ix:new_cargo_site_car_list.append(location)if location_ix == to_move_min_ix:new_cargo_site_car_list.append(to_move_max_value)# car_list 也可以在get_a_possible_try中 保存下来减少计算car_list = [car_no for (_, car_no) in sorted(cargo_car_loc2carno.items(), key=lambda x: x[0])]new_cargo_car_loc2carno = self.data.get_cargo_car_loc2carno(new_cargo_site_car_list, car_list)return new_cargo_site_car_list, new_cargo_car_loc2carnodef print_middle_reslt(self, ix, population_info):# fitness_score, car_ix_consume_time, cargo_site_car_list, cargo_car_loc2carnofitness_score = self.get_best_result(population_info)[0]print("run times %s, score is: %s" % (ix, np.mean(np.array(fitness_score))))return Nonedef print_final_result(self, population_info):# fitness_score, car_ix_consume_time, cargo_site_car_list, cargo_car_loc2carnofitness_score, _, cargo_site_car_list, cargo_car_loc2carno = self.get_best_result(population_info)print("\nGA: the final best score is %s cargo_site_car_list is %s, where the 0s represents car_list %s."% (round(fitness_score, 2), cargo_site_car_list,[car_no for (_, car_no) in sorted(cargo_car_loc2carno.items(), key=lambda x: x[0])]))if plot_flag:VRPPlot.cp_from_ins(self.data).run(cargo_site_car_list)return Nonedef get_best_result(self, population_info):population_fitness_info = self.get_fitness_by_length(population_info)population_fitness_info.sort(key=lambda x: x[0], reverse=True)# fitness_score, car_ix_consume_time, cargo_site_car_list, cargo_car_loc2carno = population_fitness_info[0]return population_fitness_info[0]class ACO(VrpHeuristic):def __init__(self, cargo_sites, cargo_site_info_dict, car_info_dict, phero_by_path_length=False):super().__init__(cargo_sites, cargo_site_info_dict, car_info_dict)# 按一般的蚁群算法介绍, phero_by_path_length 应该设为True;  这里为了解这道VRP题,设为Falseself.phero_by_path_length = phero_by_path_lengthself.phero_mat = np.ones((cargo_site_total + 1, cargo_site_total + 1))self.visible_mat = 1 / (self.distance_matrix + np.eye(cargo_site_total + 1))self.visible_mat[np.diag_indices_from(self.visible_mat)] = 0   # 对角线值置0def __call__(self):best_ants_info = Nonefor ix in range(max_iter):ants_info = []for ant_ix in range(ant_no):path, cargo_site_car_list, cargo_car_loc2carno = self.generate_path_solution(ant_ix)if not path:continuescore = self.get_fitness_info(cargo_site_car_list, cargo_car_loc2carno)cycle_distance = sum(self.get_distance_by_path([0] + path + [0]))ants_info.append((score, cycle_distance, path, cargo_site_car_list, cargo_car_loc2carno))if ants_info:# 一轮蚂蚁完成后  更新信息素best_ants_info = self.get_best_ant_info(ants_info, best_ants_info)self.update_phero_mat(ants_info)if ix % 10 == 0:print("run times %s, best score is: %s, car_no is %s, cycle_distance is %s "% (ix, best_ants_info[0], len(best_ants_info[-1]), best_ants_info[1]))self.print_final_result(best_ants_info[0], best_ants_info[-2], best_ants_info[-1])return Nonedef generate_path_solution(self, ant_ix):path = self.generate_path(ant_ix)if path:cargo_site_car_list, cargo_car_loc2carno = self.add_car_in_path(path)return path, cargo_site_car_list, cargo_car_loc2carnoreturn [], [], {}def generate_path(self, ant_ix, abnormal_threshold=1e-50, skip_abnormal=True):path = [self.get_first_cargo_site_no(ant_ix)]visited_set = set(path)while len(path) < cargo_site_total:current_site = path[-1]unvisited = [x for x in self.data.cargo_sites if x not in visited_set]result = [np.power(self.phero_mat[current_site][site], pheromone_factor_alpha) *np.power(self.visible_mat[current_site][site], visible_factor_beta)for site in unvisited]result_sum = sum(result)if result_sum < abnormal_threshold:# result_sum太小或为0 是因为 current_site 与每一个unvisited的 x y坐标隔得太远了 可能是在反方向上,# 此时 前面就错了,不应该留下来类似这种:已经跑到右上很多了,余下只有 在左下很多的货物点;# skip_abnormal为True时 放弃这一只蚂蚁 否则 仅放弃当前的路径 重新generate_path。if skip_abnormal:# print("break! give up the path!")return []path = path[:1]visited_set = set(path)continueprobs = np.cumsum(result / result_sum)index_need = np.where(probs > np.random.rand())[0][0]# 有文章说: 需要一部分蚂蚁遵循信息素最高的分配策略,还需要一部分蚂蚁遵循随机分配的策略,以发现新的局部最优解。# 所以这里也可以再加上 随机分配next_site = unvisited[index_need]path.append(next_site)visited_set.add(next_site)return pathdef get_first_cargo_site_no(self, ant_ix):# cargo_site_no 从1开始的if ant_no < cargo_site_total or (ant_ix + 1) > int(ant_no / cargo_site_total) * ant_no:return random.randint(1, cargo_site_total)else:return ant_ix % cargo_site_total + 1def get_next_cargo_site_no(self):passdef add_car_in_path(self, path):cargo_site_car_list, cargo_car_loc2carno = self.data.get_a_possible_try(path)return cargo_site_car_list, cargo_car_loc2carnodef get_best_ant_info(self, ants_info, best_ants_info=None):# ants_info:   score, cycle_distance, path, cargo_site_car_list, cargo_car_loc2carnotemp_ants_info = ants_info.copy()if best_ants_info:temp_ants_info.append(best_ants_info)if self.phero_by_path_length:# ants_info.sort(key=lambda x: x[1])temp_ants_info = sorted(temp_ants_info, key=lambda x: x[1])else:# ants_info.sort(key=lambda x: x[0], reverse=True)temp_ants_info = sorted(temp_ants_info, key=lambda x: x[0], reverse=True)return temp_ants_info[0]def update_phero_mat(self, ants_info):# phero_by_path_length时 采用蚁周模型   否则用适应度信息temp_phero_mat = np.zeros((cargo_site_total + 1, cargo_site_total + 1))for score, cycle_distance, path, cargo_site_car_list, cargo_car_loc2carno in ants_info:last_cargo_site = -1for cargo_site in path:if last_cargo_site != -1:temp = pheromone_cons / cycle_distance if self.phero_by_path_length \else pheromone_cons / (cycle_distance * - score)temp_phero_mat[last_cargo_site][cargo_site] += temptemp_phero_mat[cargo_site][last_cargo_site] += templast_cargo_site = cargo_siteself.phero_mat = (1 - volatil_factor) * self.phero_mat + temp_phero_matreturn Nonedef print_final_result(self, fitness_score, cargo_site_car_list, cargo_car_loc2carno):print("\nACO: the final best score is %s cargo_site_car_list is %s, where the 0s represents car_list %s."% (round(fitness_score, 2), cargo_site_car_list,[car_no for (_, car_no) in sorted(cargo_car_loc2carno.items(), key=lambda x: x[0])]))if plot_flag:VRPPlot.cp_from_ins(self.data).run(cargo_site_car_list)def run():cargo_sites, cargo_site_info_dict, car_info_dict = QuestionDataHandle().get_data(generate_new=generate_new_flag)if algorithm_GA:GA(cargo_sites, cargo_site_info_dict, car_info_dict)()elif algorithm_ACO:ACO(cargo_sites, cargo_site_info_dict, car_info_dict)()if __name__ == '__main__':run()

本来以为 看完理论和其他demo后, 几小时 就能写一个ACO的实现吧,没想到花了好几天时间,总觉得有不合适,也遇到好一些问题,说百转千回有夸张,但十转八回绝对太保守... 有想不明白为什么的,也有粗心造成的错。 还好有高人愿意帮我解答疑问,不然估计写不下去了..非常感谢这位朋友!:)  本想偷懒不画图的,最后觉得  还是画个图吧。画图的只在windows下跑了。

其中一个问题是  在生成路径时  跑着跑着 index_need.shape[0]会为0。 加打印日志后 看到 是因为current_site 到 unvisited 里的每一个site 的概率都为0。
第一反应的解决方法是 轮盘赌不行, 就随机选一个呗,反正是要选出来一个的,不然路径怎么继续走下去?
但觉得  不能都为0吧?好像至少应该有一个不为0? 把这时的 visible_mat 和 phero_mat都打出来看看,发现phero_mat非对角线的位置  有为0的数据,当然  还有好一些 e-237数量级的数据..  嗯,对梯度消失原因很熟悉,立即想起了 这可能是因为连乘次数太多的关系.. 
再把这些cargo_site的site_location打印出来,发现坐标点相隔较远的点 例如 (-95, -100) 和 (60, 70)。  此时他们对应位置的phero_mat的值 为0或很小。
所以,概率为0或接近于0 是正常的。 但是解决方案 不能是随机选一个,随机选 非但没正向作用,反而会引入错误,起到负向的作用。
这样的路径 前面就错了,不应该留下来类似这种:已经跑到右上很多了,余下只有 在左下很多的货物点;
此时可以 放弃当前的选择 重新generate_path 或者放弃这一只蚂蚁(实际情况中可能用这种更多 为了保证时间复杂度的估计 因为前者可能会尝试太多)。   我做了一个开关, 分别尝试的结果差不多。还是用后者。

由于另外的错误,负负得正发现  其实不需要: 到unvisited里的每一个site的概率都为0,就需要做相应的调整。比如之前看到的e-237数量级的数据,都是这么小的值,也需要调整的。那设定一个阈值吧, 不用到0, 只要小于这个很小的特定阈值,就认为路径不合理,就放弃当前path

另外 pheromone_cons的设置, 可以考虑让 pheromone_cons 与 cycle_distance 或 (cycle_distance * - score) 在一个靠近点的数量级上。 
比如最开始时, 我是设为1的,因为 cycle_distance的数量级是几百上千, score数量级也是几百, 后来改为了100

关于蚁周蚁量蚁密模型, 可能蚁密模型 是与一般最开始的介绍文档最符合的,就是模访自然界里的蚂蚁  跑一次是一个常量。但是可能是最不合适使用的模型。一般最开始的介绍文档说的 都是短路径上的信息素 最多,那是因为假设了 蚂蚁从起点到终点后  会立即再启程重新往返, 所以在同样的时间, 短路径被跑的多, 信息素最多。但我们这样的代码,一个迭代每只蚂蚁都只寻找一次路径,并没有来回往返寻找。

蚁量模型 可能更容易陷入局部最优;蚁周模型 考虑全局的信息更多。我选用的蚁周模型。如果是一般的蚁群算法hello world实现, phero_by_path_length 可以设为True; 这里为了解这道VRP题,设为False, 信息素的更新,使用的综合的fitness信息。

某一次运行后的图:

把之前的遗传算法实现 也合并到里面了,有点长..  本来肯定应该是要分文件夹和代码文件配置文件的,但.. 请暂时忍忍吧

------------------

最近被问到 依赖倒置原则。现在的代码里,比如VRPPlot类里直接使用了VRPData的实例,而VRPData不是一个抽象类或普通基类。 这里VRPData类 有平行维度的实现/替换 的可能性比较小,不过确实还是需要考虑:如果未来Data类可能会出现另一种可能的实现,这里(VRPPlot类)最好使用一个抽象类或普通基类的实例, 而VRPData继承这个抽象类或普通基类。 对于VRPPlot,同样可以视情况决定 是否需要使用抽象和继承。

蚁群算法一个VRP小实现相关推荐

  1. 蚁群算法matlab vrp问题车辆限重,蚁群算法MATLAB解VRP问题

    Excel  exp12_3_2.xls内容: ANT_VRP函数: function [R_best,L_best,L_ave,Shortest_Route,Shortest_Length]=ANT ...

  2. vrp车辆路径问题 php,蚁群算法在车辆路径问题(VRP)中的应用.ppt

    蚁群算法在车辆路径问题(VRP)中的应用 ◆割平面法(Cutting Planes Approach)[6] 割平面法求解VRP问题(A)的基本思想是,在求解相应的不含整数约束的VRP问题(B)上,增 ...

  3. 关于精英蚁群算法matlab,蚁群算法MATLAB解VRP问题

    Excel  exp12_3_2.xls内容: ANT_VRP函数: function [R_best,L_best,L_ave,Shortest_Route,Shortest_Length]=ANT ...

  4. 蚁群算法求解路径优化问题

    蚁群算法求解CVRP问题matlab代码,可直接运行 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Markdown编辑器, 可 ...

  5. Python实现VRP常见求解算法——蚁群算法(ACO)

    基于python语言,实现经典蚁群算法(ACO)对车辆路径规划问题(CVRP)进行求解. 目录 优质资源 1. 适用场景 2. 求解效果 3. 问题分析 4. 数据格式 5. 分步实现 6. 完整代码 ...

  6. 【信号去噪】基于蚁群算法优化小波阈值实现信号去噪附matlab代码

    1 简介 基于硬阈函数和软阈函数的小波去噪算法处理的信号分别存在着偏差和方差过大的缺点,为有效解决这一问题,提出基于蚁群算法优化小波变换去噪算法.并采用常用的信号用matlab对去噪效果进行了仿真.仿 ...

  7. 蚁群算法Ant Colony Optimization-ACO

    蚁群算法是一种用来寻找优化路径的概率型算法.它由Marco Dorigo于1992年在他的博士论文中提出,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为.这种算法具有分布计算.信息正反馈和启发式搜索的 ...

  8. 【配送路径规划】蚁群算法求解配送路径最短问题【含Matlab源码 2222期】

    ⛄一.VRP简介 1 VRP基本原理 车辆路径规划问题(Vehicle Routing Problem,VRP)是运筹学里重要的研究问题之一.VRP关注有一个供货商与K个销售点的路径规划的情况,可以简 ...

  9. 【配送路径规划】基于matlab蚁群算法求解配送路径最短问题【含Matlab源码 2222期】

    ⛄一.VRP简介 1 VRP基本原理 车辆路径规划问题(Vehicle Routing Problem,VRP)是运筹学里重要的研究问题之一.VRP关注有一个供货商与K个销售点的路径规划的情况,可以简 ...

最新文章

  1. 警惕黑客破坏网络安全
  2. 谭浩强课后题之----判断闰年
  3. php怎样输出多个空格,【整理】解决php输出时出现多余的空格或者换行
  4. 如何通俗理解计算机视觉、计算机图形、图像处理之间的区别与联系
  5. 【跃迁之路】【425天】程序员高效学习方法论探索系列(实验阶段182-2018.04.06)...
  6. matlab分析xml文件_如何在Java中读取XML文件(DOM分析器)
  7. 2019年9月全国程序员工资统计,你处于什么位置?
  8. 事务实例--银行转账
  9. Linux下原生异步IO接口Libaio的用法
  10. Macbook Pro touch bar 设置小tips
  11. 【Scala】Scala中的模式匹配、类型参数与隐式转换
  12. golang 模拟键盘输入
  13. 计算机病毒计算机软件系统故障,简要区分计算机病毒与软硬件故障问题
  14. 4438的代码分析一
  15. explicit c++
  16. C语言中字符串和字符数组的区别
  17. 基于java中国象棋游戏
  18. 织梦网站后台基本设置
  19. 将数组中的对象按照浏览器的x/y轴的显示方式进行排序
  20. powermock跳过某方法_如何使用powermock验证内部方法调用?

热门文章

  1. 万字拆解自嗨锅:造价近百万的直播间,是单场直播GMV破100万的法门吗?
  2. 项目国际化I18N多语言切换
  3. 双系统linux触摸板不能用,windows系统与ubuntu双系统导致笔记本触摸板失灵的解决办法(非输入代码)...
  4. 【AI应用】理解GPU的浮点计算能力
  5. 透彻分析微信公众平台三大矛盾
  6. 富文本粘贴word文档内容图片处理
  7. Cesium 可视域分析代码段(源码)补充
  8. python英语词汇读音_利用PYTHON 爬虫爬出自己的英语单词库
  9. html设置字段只读,html怎么设置只读
  10. php更换鼠标指针详细,window_Win7系统鼠标指针怎么更改?Win7系统更换鼠标指针的方法,  Win7系统鼠标指针怎么更改 - phpStudy...