蚁群算法解决旅行商问题

  • 什么是旅行商问题
  • 蚁群算法概述
  • 代码实现

蚁群算法学习视频
YouTube:【数之道 04】解决最优路径问题的妙招-蚁群ACO算法

什么是旅行商问题

  旅行商问题(英语:Travelling salesman problem, TSP)是组合优化中的一个NP困难问题,在运筹学和理论电脑科学中非常重要。问题内容为“给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。”

  问题在1930年首次被形式化,并且是在最优化中研究最深入的问题之一。许多优化方法都用它作为一个基准。尽管问题在计算上很困难,但已经有了大量的启发式和精确方法,因此可以完全求解城市数量上万的实例,并且甚至能在误差1%范围内估计上百万个城市的问题。

  甚至纯粹形式的TSP都有若干应用,如企划、物流、芯片制造。稍作修改,就是DNA测序等许多领域的一个子问题。在这些应用中,“城市”的概念用来表示客户、焊接点或DNA片段,而“距离”的概念表示旅行时间或成本或DNA片段之间的相似性度量。TSP还用在天文学中,观察很多光源的天文学家会希望减少在不同光源之间转动望远镜的时间。在许多应用场景中(如资源或时间窗口有限等等),可能会需要加入额外的约束条件。

  经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。从图论的角度来看,该问题实质是在一个带权完全无向图中,找一个权值最小的Hamilton回路。由于该问题的可行解是所有顶点的全排列,随着顶点数的增加,会产生组合爆炸,它是一个NP完全问题。由于其在交通运输、电路板线路设计以及物流配送等领域内有着广泛的应用,国内外学者对其进行了大量的研究。

  早期的研究者使用精确算法求解该问题,常用的方法包括:分枝定界法、线性规划法、动态规划法等。但是,随着问题规模的增大,精确算法将变得无能为力,因此,在后来的研究中,国内外学者重点使用近似算法或启发式算法,主要有遗传算法、模拟退火法、蚁群算法、禁忌搜索算法、贪婪算法和神经网络等。

蚁群算法概述

  蚁群在外出觅食或者探索的时候,往往会留下弗洛蒙(信息素),每当该蚂蚁在此路径有良好的发现,就会将弗洛蒙浓度加大;反之,弗洛蒙浓度则会挥发,蚁群算法就是根据这一特点而被设计出来的。

首先我们对蚂蚁的功能进行定义:

  1. 蚂蚁在一个旅程中不会访问相同的城市
  2. 蚂蚁可以知晓城市之间的距离
  3. 蚂蚁会在其走过的路上释放弗洛蒙(信息素)

之后建立函数 PijkP_{ij}^kPijk​ 表示第k只蚂蚁从状态 iii 转移至状态 jjj 的概率
公式如下:
    Pijk=(τijα)(ηijβ)∑zϵallowedx(τijα)(ηijβ)P_{ij}^k=\frac {(\tau _{ij}^\alpha)(\eta_{ij}^\beta)}{\sum_{z\epsilon allowedx }(\tau _{ij}^\alpha)(\eta_{ij}^\beta)}Pijk​=∑zϵallowedx​(τijα​)(ηijβ​)(τijα​)(ηijβ​)​

其中τij\tau_{ij}τij​为弗洛蒙浓度,ηij\eta_{ij}ηij​为距离

  • 其弗洛蒙浓度计算公式:
    τij(t+1)=ρ∗τij(t)+△τij\tau_{ij}(t+1)=\rho*\tau_{ij}(t)+\triangle\tau_{ij}τij​(t+1)=ρ∗τij​(t)+△τij​
    其中ρ\rhoρ为佛罗蒙浓度挥发系数,△τij\triangle\tau_{ij}△τij​为此次佛罗蒙浓度变化值
    △τij=QLk\triangle\tau_{ij}={{Q}\over{L_k}}△τij​=Lk​Q​ 其中Q为信息素增加强度系数,LkL_kLk​为上期蚂蚁循环总路程
    由上式可见,蚂蚁走过的路程越短与信息素浓度成反比;Q与信息素浓度成正比
    又因为有kkk只蚂蚁,所以总△τij\triangle\tau_{ij}△τij​为:
    △τij=∑k=1m△τijk\triangle\tau_{ij}=\sum_{k=1}^m\triangle\tau_{ij}^k△τij​=∑k=1m​△τijk​

  • 距离计算公式:
    ηij=1dij\eta_{ij}={1\over{d_{ij}}}ηij​=dij​1​
    可见,距离越短,ηij\eta_{ij}ηij​越大

  • 公式中α\alphaα和β\betaβ为权重控制系数
    当α\alphaα为0时,完全根据城市距离做选择,一般都是局部最优,很难得到全局最优
    当β\betaβ为0时,完全根据佛罗蒙浓度做选择,程序迭代往往会以很快的速度收敛,很难达到预期效果

所以一般在使用蚁群算法时,我们要设定合适的α,β,η,τ,Q\alpha,\beta,\eta,\tau,Qα,β,η,τ,Q去获得很好的解

代码实现

此次实验以下图进行示例演示(哈哈,其实是因为课程要求是这个,偷个懒)

我代码全部附在下方,需要自行复制即可,或在该链接
github:https://github.com/Junzhou-Chen/Ant-Colony-Algorithm
CSDN:https://download.csdn.net/download/weixin_51717597/85587476
自行下载,这里我对各别部分进行说明,其余地方注释详尽,自行查看即可
其中utils.py为可视化方法文件,主要打印程序运行时间、结果等文字,同时现实蚁群算法规划的路线图:


之后是ACO函数,即为蚁群算法的核心算法代码,调用时调用antColonyOptimization接口即可,接口相关解释如下:

def antColonyOptimization(cityNum, coordinate, point, setting):"""蚁群算法:param cityNum: 城市数量 int:param coordinate: 城市坐标 list:param point: 城市距离矩阵 ndarray:param setting: 函数相关配置 obj:return: 最小距离 double, 运行时间 double, 迭代次数 intsetting相关配置:iter_max: 最大迭代次数 intifOptimanation: 是否使用简单优化后的方案 boolthreshold: 阈值 intskipNum: 达到阈值后跳过的迭代次数 int示例:setting = {"iter_max": 500,"ifOptimanation": True,"threshold": 6,"skipNum": 20}"""

最后为主函数demo.py,这里我就将旅行商地图赋值加入,其蚁群算法计算主要依赖point路径矩阵进行计算,coordinate为可视化中点的位置
demo.py:

import ACO
import numpy as np# 旅行商测试矩阵
#   1   2   3   4   5   6
# 1 0   6   2   1   MAX MAX
# 2 6   0   6   MAX 3   MAX
# 3 2   6   0   2   2   4
# 4 1   MAX 2   0   MAX 5
# 5 MAX 3   2   MAX 0   3
# 6 MAX MAX 4   5   3   0# 旅行商初始化函数,总共6个城市
def InitD():cityNum = 6coordinate = [(4, 7.5), (0, 5.5), (5, 4), (10, 5.5), (1.5, 1), (11, 0)]MAX_INT = 1e8point = np.array([[0, 6, 2, 1, MAX_INT, MAX_INT], [6, 0, 6, MAX_INT, 3, MAX_INT], [2, 6, 0, 2, 2, 4],[1, MAX_INT, 2, 0, MAX_INT, 5], [MAX_INT, 3, 2, MAX_INT, 0, 3], [MAX_INT, MAX_INT, 4, 5, 3, 0]])return cityNum, coordinate, pointdef ACOTest():cityNum, coordinate, point = InitD()ACO.antColonyOptimization(cityNum, coordinate, point, setting={"iter_max": 300,"ifOptimanation": False,"threshold": 6,"skipNum": 20})if __name__ == '__main__':ACOTest()

ACO.py:

import random
import timeimport numpy as npimport utils  # 自定义工具函数包# 蚂蚁数为城市数的2 / 3
num_ant = 4    # 蚂蚁数量
alpha = 2  # 信息素影响因子,选择[1, 5]比较合适
beta = 1  # 期望影响因子,选择[1, 5]比较合适
info = 0.3  # 信息素的挥发率,选择0.3比较合适
Q = 5  # 信息素增加强度系数inf = 1e8  # 定义无穷大值
def cal_newpath(dis_mat, path_new, cityNum):"""计算所有路径对应的距离:param dis_mat: 城市距离矩阵 ndarray:param path_new: 路径矩阵 ndarray:param cityNum: 城市数量 int:return: 动态规划最优路径 list"""dis_list = []for each in path_new:dis = 0for j in range(cityNum - 1):dis = dis_mat[each[j]][each[j + 1]] + disdis = dis_mat[each[cityNum - 1]][each[0]] + dis  # 回家dis_list.append(dis)return dis_listdef getDisAndPath(point, cityNum, setting):"""计算所有路径对应的距离:param point: 城市距离矩阵 ndarray:param cityNum: 城市数量 int:param setting: 函数相关配置 obj, 见antColonyOptimization的setting:return: 最短路径值 double 最短路径 list"""dis_mat = np.array(point)  # 转为矩阵# 期望矩阵e_mat_init = 1.0 / (dis_mat + np.diag([10000] * cityNum))  # 加对角阵是因为除数不能是0diag = np.diag([1.0 / 10000] * cityNum)e_mat = e_mat_init - diag  # 还是把对角元素变成0pheromone_mat = np.ones((cityNum, cityNum))  # 初始化每条边的信息素浓度,全1矩阵path_mat = np.zeros((num_ant, cityNum)).astype(int)  # 初始化每只蚂蚁路径,都从0城市出发count_iter = 0# 设置了一个统计连续多次没有产生更优解的计数器counter,如果当前迭代产生的解与上一次迭代产生的解相同,counter的值加1,当counter的值大于某一阈值threshold时,减少迭代次数skipNum次,同时counter清零。counter = 0  # 蚁群迭代次数简单优化方案的计数器ifOptimanation = setting["ifOptimanation"]threshold = setting["threshold"]iter_max = setting["iter_max"]skipNum = setting["skipNum"]pre_min_path = 0while count_iter < iter_max:for ant in range(num_ant):visit = 0  # 都从0城市出发unvisit_list = list(range(1, cityNum))  # 未访问的城市for j in range(1, cityNum):# 轮盘法选择下一个城市trans_list = []tran_sum = 0trans = 0for k in range(len(unvisit_list)):trans += np.power(pheromone_mat[visit][unvisit_list[k]], alpha) * np.power(e_mat[visit][unvisit_list[k]], beta)trans_list.append(trans)tran_sum = transrand = random.uniform(0, tran_sum)  # 产生随机数for t in range(len(trans_list)):if rand <= trans_list[t]:visit_next = unvisit_list[t]breakelse:continuepath_mat[ant, j] = visit_next  # 填路径矩阵unvisit_list.remove(visit_next)  # 更新visit = visit_next  # 更新# 所有蚂蚁的路径表填满之后,算每只蚂蚁的总距离dis_allant_list = cal_newpath(dis_mat, path_mat, cityNum)# 每次迭代更新最短距离和最短路径if count_iter == 0:dis_new = min(dis_allant_list)path_new = path_mat[dis_allant_list.index(dis_new)].copy()else:if min(dis_allant_list) < dis_new:dis_new = min(dis_allant_list)path_new = path_mat[dis_allant_list.index(dis_new)].copy()# 蚁群算法迭代次数的简单优化if ifOptimanation == True:if round(pre_min_path, 2) == round(dis_new, 2):counter += 1if counter >= threshold:iter_max -= skipNumcounter = 0pre_min_path = dis_new# 更新信息素矩阵pheromone_change = np.zeros((cityNum, cityNum))for i in range(num_ant):for j in range(cityNum - 1):pheromone_change[path_mat[i, j]][path_mat[i, j + 1]] += Q / dis_mat[path_mat[i, j]][path_mat[i, j + 1]]pheromone_change[path_mat[i, cityNum - 1]][path_mat[i, 0]] += Q / dis_mat[path_mat[i, cityNum - 1]][path_mat[i, 0]]pheromone_mat = (1 - info) * pheromone_mat + pheromone_changecount_iter += 1  # 迭代计数+1,进入下一次return dis_new, path_new.tolist(), iter_maxdef antColonyOptimization(cityNum, coordinate, point, setting):"""蚁群算法:param cityNum: 城市数量 int:param coordinate: 城市坐标 list:param point: 城市距离矩阵 ndarray:param setting: 函数相关配置 obj:return: 最小距离 double, 运行时间 double, 迭代次数 intsetting相关配置:iter_max: 最大迭代次数 intifOptimanation: 是否使用简单优化后的方案 boolthreshold: 阈值 intskipNum: 达到阈值后跳过的迭代次数 int示例:setting = {"iter_max": 500,"ifOptimanation": True,"threshold": 6,"skipNum": 20}"""start = time.perf_counter()  # 程序开始时间# skipNum次数为1 5 10 15dis, path, iterNum = getDisAndPath(point, cityNum, setting)end = time.perf_counter()  # 程序结束时间utils.printTable(path, 7, end - start, cityNum, round(dis, 2))  # 打印表格utils.drawNetwork(coordinate, point, path, inf)return round(dis, 2), end - start, iterNum

untils.py:

import matplotlib.pyplot as plt
import networkx as nx
from prettytable import PrettyTable# 打印旅行商问题的运行结果表格def createTable(table_obj):"""打印数据表格:param table_obj: 表格对象 obj:return: none参数示例:result_obj = {"header": ["TSP参数", "运行结果"],"body": [["城市数量", cityNum],["最短路程", distance],["运行时间", time_str],["最小路径", path_str]],# name的值要和header一致, l: 左对齐 c: 居中 r: 右对齐"align": [{ "name": "TSP参数", "method": "l" },{ "name": "运行结果", "method": "l" }],"setting": {"border": True, # 默认True"header": True, # 默认True"padding_width": 5 # 空白宽度}}"""pt = PrettyTable()for key in table_obj:# 打印表头if key == "header":pt.field_names = table_obj[key]# 打印表格数据elif key == "body":for i in range(len(table_obj[key])):pt.add_row(table_obj[key][i])# 表格参数的对齐方式elif key == "align":for i in range(len(table_obj[key])): pt.align[table_obj[key][i]["name"]] = table_obj[key][i]["method"]# 表格其他设置elif key == "setting":for key1 in table_obj[key]:if key1 == "border":pt.border = table_obj[key][key1]elif key1 == "hearder":pt.header = table_obj[key][key1]elif key1 == "padding_width":pt.padding_width = table_obj[key][key1]# for key1 in table_obj[key]: pt[key1] = table_obj[key][key1]print(pt)# survive
def timeFormat(number):"""时间格式保持两位:param number: 数字 int:return: 两位的数字字符 str"""if number < 10:return "0" + str(number)else:return str(number)def calcTime(time):"""将毫秒根据数值大小转为合适的单位:param time: 数字 double:return: 时间字符串 str"""count = 0while time < 1:if count == 3:breakelse:count += 1time *= 1000if count == 0:hour = int(time // 3600)minute = int(time % 3600 // 60)second = time % 60if hour > 0: return timeFormat(hour) + "时" + timeFormat(minute) + "分" + timeFormat(int(second)) + "秒"if minute > 0: return timeFormat(minute) + "分" + timeFormat(int(second)) + "秒"if second > 0: return str(round(time, 3)) + "秒"elif count == 1:return str(round(time, 3)) + "毫秒"elif count == 2:return str(round(time, 3)) + "微秒"elif count == 3:return str(round(time, 3)) + "纳秒"# survive
def pathToString(path, everyRowNum):"""将最优路径列表转为字符串:param everyRowNum::param path: 最优路径列表 list:param: everyRowNum 每行打印的路径数,除去头尾 int:return: 路径字符串 str"""min_path_str = ""for i in range(len(path)):min_path_str += str(path[i] + 1) + ("\n--> " if i != 0 and i % everyRowNum == 0 else " --> ")min_path_str += "1"  # 单独输出起点编号return min_path_str# 打印表格
def printTable(path, everyRowNum, runTime, cityNum, distance):"""将最优路径列表转为字符串:param: path: 最优路径列表 list:param: everyRowNum 每行打印的路径数,除去头尾 int:param: runTime 程序运行时间 double:param: cityNum 城市数量 int:param: distance 最优距离 double:return: none"""path_str = pathToString(path, everyRowNum)time_str = calcTime(runTime)  # 程序耗时# 打印的表格对象result_obj = {"header": ["TSP参数", "运行结果"],"body": [["城市数量", cityNum],["最短路程", distance],  # 最小值就在第一行最后一个["运行时间", time_str],  # 计算程序执行时间["最小路径", path_str]  # 输出路径],"align": [{"name": "参数", "method": "l"},{"name": "运行结果", "method": "l"}],}createTable(result_obj)  # 打印结果###########################################################################
# 画图函数def isPath(path, i, j):"""判断边是否为最小路径:param path: 最优路径列表 list:param: i / j 路径的下标 int:return: 布尔值"""idx = path.index(i)pre_idx = idx - 1 if idx - 1 >= 0 else len(path) - 1next_idx = idx + 1 if idx + 1 < len(path) else 0if j == path[pre_idx] or j == path[next_idx]:return Truereturn Falsedef drawNetwork(coordinate, point, path, inf, *args):"""画出网络图:param coordinate: 城市坐标 list:param: point 城市距离矩阵 ndarray:param: path 最优路径 list:param: inf 无穷大值 double:return: none"""G_min = nx.Graph()  # 最短路径解G = nx.Graph()  # 城市路径图edges = []for i in range(len(coordinate)):m = i + 1G_min.add_node(m, pos=coordinate[i])  # 添加节点G.add_node(m, pos=coordinate[i])for j in range(i + 1, len(coordinate)):if point[i][j] != inf:if isPath(path, i, j):G_min.add_edge(i + 1, j + 1, weight=int(point[i][j]), color='r')G.add_edge(i + 1, j + 1, weight=int(point[i][j]))tmp_edges = nx.get_edge_attributes(G_min, 'color')for key in tmp_edges:edges.append(tmp_edges[key])pos = pos_min = nx.get_node_attributes(G_min, 'pos')labels = nx.get_edge_attributes(G_min, 'weight')label = nx.get_edge_attributes(G, 'weight')# 城市所有路径plt.subplot(121)plt.title("TSP City Network")nx.draw(G, pos, with_labels=True, font_weight='bold', node_color='y')nx.draw_networkx_edge_labels(G, pos, edge_labels=label)  # 画路径长度# 最短路径解plt.subplot(122)plt.title("Solution Of Ant Colony Algorithm")nx.draw(G_min, pos_min, with_labels=True, font_weight='bold', node_color='g', edge_color=edges)nx.draw_networkx_edge_labels(G_min, pos_min, edge_labels=labels)  # 画路径长度plt.show()

蚁群算法解决旅行商问题Python相关推荐

  1. 集货运输优化:数学建模步骤,Python实现蚁群算法(解决最短路径问题), 蚁群算法解决旅行商问题(最优路径问题),节约里程算法

    目录 数学建模步骤 Python实现蚁群算法(解决最短路径问题) 蚁群算法解决旅行商问题(最优路径问题) 节约里程算法

  2. 【路径规划-TSP问题】基于粒子群结合蚁群算法求解旅行商问题附matlab代码

    1 内容介绍 一种基于粒子群优化的蚁群算法求解TSP问题的方法.该方法在求解TSP问题时,利用粒子群优化的思想,对蚁群算法的参数取值进行优化并选择.在粒子群算法中,将蚁群算法的5个参数(q,α,β,ρ ...

  3. 【ACO TSP】基于matlab GUI蚁群算法求解旅行商问题【含Matlab源码 1032期】

    ⛄一.TSP简介 旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...

  4. 基于蚁群算法解决多模式资源约束项目调度问题(附源代码)

    基于蚁群算法解决多模式资源约束项目调度问题 最近选修了张超勇教授的项目管理学,最后这门课留下了一门大作业,这里我选做是资源约束下的项目调度问题,通过使用元启发式的蚁群算法求解了这个问题,由于时间比较仓 ...

  5. 蚂蚁算法求解tsp问题matlab,蚁群算法解决TSP问题的MATLAB程序

    蚁群算法TSP(旅行商问题)通用matlab程序 function [R_best,L_best,L_ave,Shortest_Route,Shortest_Length]=ACATSP(C,NC_m ...

  6. 蚁群算法解决tsp问题c语言,蚁群算法解决TSP问题程序.doc

    蚁群算法解决TSP问题程序 蚁群算法用于求解TSP问题,经过仿真测试,发现此程序的优化效率和鲁棒性都非常好. 这与在无线多媒体传感器网络路由算法应用到的寻找最佳路径的蚁群算法非常相似. functio ...

  7. 蚁群算法解决tsp问题python_蚁群算法在解决TSP问题中的应用

    陈灵佳 文章首先对蚁群算法与TSP问题进行简要介绍,在此基础上对蚁群算法在解决TSP问题中的应用进行论述.期望通过本文的研究能够对TSP问题的解决有所帮助. [关键词]蚁群算法 TSP问题 最优解 1 ...

  8. 蚁群算法解决 TSP 问题

    蚁群算法解决 TSP 问题 数据集 Tools.py Ant.py ACO_G.py 运行效果 数据集 json 形式(c.json)的中国各省市经纬度数据集,一共 2241 个市的数据,为后来的 T ...

  9. 【ACO TSP】基于matlab改进的蚁群算法求解旅行商问题【含Matlab源码 242期】

    ⛄一.TSP简介 旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...

最新文章

  1. 想做数据分析?这个比赛适合你!
  2. java重要基础知识点_必看 | 新人必看的Java基础知识点大梳理
  3. https是如何保证数据传输的安全
  4. 我来发美食啦,馋一下各位看官
  5. mysql参数优化51cto_超详细MySQL数据库优化
  6. paho.mqtt.embedded-c-master c语言版本架构
  7. View onRestoreInstanceState ClassCastException
  8. 画毛毛虫代码计算机图形学,考试计算机图形学考试计算机图形学.docx
  9. 初识C++之运算符重载
  10. 使用 Autofill 插件快速提交BUG
  11. 第四季-专题13-总线设备驱动模型
  12. java, android的aes等加密库
  13. iconpath 微信小程序_微信小程序 底部导航栏
  14. pycharm 运行celery_调试celery遇到的坑
  15. 微信wifi认证的实现方式和功能——时讯wifi认证
  16. Python 人工智能:16~20
  17. python中有这样一条语句_在Python中一行书写两条语句时,语句之间可以使用__________作为分隔符。_学小易找答案...
  18. leetcode881.救生艇(中等)
  19. 攻防世界 pwn进阶区----No.012 babyfengshui 解题思路
  20. 「csp模拟试题 201903-2」二十四点 C/C++ 100分

热门文章

  1. 眼睛里招人恼怒的“蚊子”,可以用眼药水治疗吗?
  2. 安装Oracle数据库客户端时出现:INS-13001环境不满足最低要求问题
  3. win10安装Oracle11g提示INS-13001 环境不满足最低要求的解决方案
  4. 大众点评网站源码_与大众分享您的网站
  5. 中国历史上死得最窝囊的九个英雄
  6. jquery 对象不支持此属性或方法
  7. 【Hadoop】基于Hadoop/Hbase/Hive的小型离线服务器日志分析应用
  8. STM32 |显示:API is not found, corresponding pack is missing or not selected
  9. 捷通华声笔试面试里做得不好的题总结
  10. SimNow CTP 环境备份