【建模算法】基于蚁群算法(ACA)求解TSP问题(Python实现)

TSP (traveling salesman problem,旅行商问题)是典型的NP完全问题,即其最坏情况下的时间复杂度随着问题规模的增大按指数方式增长,到目前为止还未找到一个多项式时间的有效算法。本文探讨了基于蚁群算法求解TSP问题的Python实现。

一、问题描述

​ 本案例以31个城市为例,假定31个城市的位置坐标如表1所列。寻找出一条最短的遍历31个城市的路径。

城市编号 X坐标 Y坐标 城市编号 X坐标 Y坐标
1 1.304 2.312 17 3.918 2.179
2 3.639 1.315 18 4.061 2.37
3 4.177 2.244 19 3.78 2.212
4 3.712 1.399 20 3.676 2.578
5 3.488 1.535 21 4.029 2.838
6 3.326 1.556 22 4.263 2.931
7 3.238 1.229 23 3.429 1.908
8 4.196 1.044 24 3.507 2.376
9 4.312 0.79 25 3.394 2.643
10 4.386 0.57 26 3.439 3.201
11 3.007 1.97 27 2.935 3.24
12 2.562 1.756 28 3.14 3.55
13 2.788 1.491 29 2.545 2.357
14 2.381 1.676 30 2.778 2.826
15 1.332 0.695 31 2.37 2.975
16 3.715 1.678

二、蚁群算法简介

2.1 蚁群算法基本原理

1、蚂蚁在行走过程中会依据信息素来选择道路,选择信息素较浓的路走,并且在行走的路径中会释放信息素,对于所有蚂蚁都没经过的路,则随机选择一条路走;
2、蚂蚁释放的信息素浓度与长度相关,通常与路径长度成反比;
3、信息素浓的路径会受到蚂蚁更大概率的选择,形成正向反馈,最短路径上的信息素浓度会越来越大,最终蚁群就都按这条最短路径走。

信息素计算公式、转移概率、信息素重要程度因子、启发函数重要程度因子、信息素挥发因子等详细介绍可参考"蚁群算法详细讲解"和“TSP解决之道——蚁群算法”

2.2 算法的两个关键步骤

1、选择:为蚂蚁选择下一个城市,信息素越多的路径被选中概率较大,可用轮盘赌算法实现;
2、信息素更新:一段时间后(蚂蚁走完一个城市或者走完整个路径后)重新计算信息素(计算方法:历史累计信息素-信息素挥发量+蚂蚁行走释放量),蚂蚁行走释放量的常见方法有三种:蚁周算法(ant-cycle,蚂蚁走完整个路径后,蚂蚁行走释放部分用Q/L计算,Q表示蚂蚁释放信息素的量,为常量,L表示路径总长度)、蚁密算法(ant-density,蚂蚁走完一个城市后,蚂蚁行走释放用Q表示)、蚁量算法(ant-quantity,蚂蚁走完一个城市后,蚂蚁行走释放用Q/dij表示,dij表示城市i和j之间的距离)。

三、蚁群算法设计

在本算法设计中,包含两层循环,外循环是迭代次数循环,内循环遍历每一只蚂蚁,其中信息素增量在每一只蚂蚁走完整体路径后对当前信息素更新,而信息素挥发只在每一代蚂蚁都走完后对当前信息素更新,流程如下:

四、求解结果

最优路线与最优值:

最优轨迹图:

五、Python源代码

#蚁群算法求解31座城市TSP问题完整代码:
import numpy as np
import pandas as pd
import math
import matplotlib.pyplot as plt
from time import perf_counterclass AntList(object):def __init__(self,distfunc,getEtatable,numant=5,numcity=10,alpha=1,rho=0.1,Q=1):""" 构造函数 """self.numant = numant        # 蚂蚁个数self.numcity = numcity        # 城市个数self.alpha = alpha            # 信息素重要程度因子self.rho = rho                # 信息素的挥发速度self.Q = Q                    # 品质因子self.distfunc=distfuncself.getEtatable=getEtatableself.bestantunit=Noneself.population=[]self.pathtable = np.zeros((self.numant,self.numcity)).astype(int)    # 路径记录表self.generation=0def Init_eta_phe(self):"""函数名:Init_eta_phe(self)函数功能:    对启发函数和信息素进行初始化"""self.etatable = self.getEtatable()            # 启发函数矩阵,表示蚂蚁从城市i转移到矩阵j的期望程度self.pheromonetable  = np.ones((self.numcity,self.numcity))            # 信息素矩阵def InitStartPosition(self):"""函数名:InitStartPosition(self)函数功能:    初始化蚂蚁的起始位置"""#  随机产生各个蚂蚁的起点城市if self.numant <= self.numcity:       # 城市数比蚂蚁数多self.pathtable[:,0] = np.random.permutation(range(0,self.numcity))[:self.numant]else:                               # 蚂蚁数比城市数多,需要补足self.pathtable[:self.numcity,0] = np.random.permutation(range(0,self.numcity))[:]self.pathtable[self.numcity:,0] = np.random.permutation(range(0,self.numcity))[:self.numant-self.numcity]def upDateInf(self):"""函数名:upDateInf(self)函数功能:    对信息素进行更新"""changepheromonetable = np.zeros((self.numcity,self.numcity))if self.population:for antunit in self.population:for i in range(self.numcity-1):changepheromonetable[antunit.path[i]][antunit.path[i+1]] += self.Q/antunit.lengthchangepheromonetable[antunit.path[self.numcity-1]][antunit.path[0]] += self.Q/antunit.lengthself.pheromonetable = (1-self.rho)*self.pheromonetable + changepheromonetableelse:self.Init_eta_phe()def getNextCity(self,unvisited,visiting):"""函数名:getNextCity(self,unvisited,visiting)函数功能:    根据信息素和启发函数矩阵,通过轮盘赌法随机选下一个城市输入    1     self:类自身输入 2    unvisited:未走过的城市列表输入 2    visited:已经走过的城市列表输出    1    k:下一个城市的编号其他说明:无"""listunvisited = list(unvisited)probtrans = np.zeros(len(listunvisited))for k in range(len(listunvisited)):probtrans[k] = np.power(self.pheromonetable[visiting][listunvisited[k]],self.alpha)\*np.power(self.etatable[visiting][listunvisited[k]],self.alpha)cumsumprobtrans = (probtrans/sum(probtrans)).cumsum()cumsumprobtrans -= np.random.rand()k = listunvisited[np.where(cumsumprobtrans>0)[0][0]] # 下一个要访问的城市return kdef GoOnePath(self,i):"""函数名:distance(self, path)函数功能:    第i只蚂蚁从随机点出发找到一条路径输入    1     self:类自身输入 2    i:当代的第i只蚂蚁输出    1    antunit:一个蚂蚁单元类其他说明:无"""visiting = self.pathtable[i,0]        # 当前所在的城市unvisited = set(range(self.numcity))# 未访问的城市unvisited.remove(visiting)            # 删除元素for j in range(1,self.numcity):        # 循环numcity-1次,访问剩余的numcity-1个城市# 每次用轮盘法选择下一个要访问的城市k=self.getNextCity(unvisited,visiting)self.pathtable[i,j] = kunvisited.remove(k)visiting = kantunit=AntUnit(self.pathtable[i],self.distfunc(self.pathtable[i]))if self.bestantunit:if self.bestantunit.length>antunit.length:self.bestantunit=antunitelse:self.bestantunit=antunitreturn antunitdef nextGeneration(self):"""函数名:nextGeneration(self)函数功能:    产生下一代"""self.upDateInf()newPopulation = []                        # 新种群for i in range(self.numant):newPopulation.append(self.GoOnePath(i))self.population = newPopulationself.generation += 1class AntUnit(object):"""类名:GAUnit类说明:    遗传算法个体类"""def __init__(self, aPath = None,aLength = -1):""" 构造函数 """self.path = list(aPath)            # 个体的基因序列self.length = aLength              # 初始化适配值class Node:"""类名:Node类说明:    城市节点类"""def __init__(self,CityNum):"""函数名:GetData()函数功能:    从外界读取城市数据并处理输入    无输出    1 Position:各个城市的位置矩阵2 CityNum:城市数量3 Dist:城市间距离矩阵其他说明:无"""self.visited=[False]*CityNum    #记录城市是否走过self.start=0                    #起点城市self.end=0                      #目标城市self.current=0                  #当前所处城市self.num=0                      #走过的城市数量self.pathsum=0                  #走过的总路程self.lb=0                       #当前结点的下界self.listc=[]                   #记录依次走过的城市def GetData(datapath):"""函数名:GetData()函数功能:    从外界读取城市数据并处理输入    无输出    1 Position:各个城市的位置矩阵2 CityNum:城市数量3 Dist:城市间距离矩阵其他说明:无"""dataframe = pd.read_csv(datapath,sep=" ",header=None)Cities = dataframe.iloc[:,1:3]Position= np.array(Cities)                #从城市A到B的距离矩阵CityNum=Position.shape[0]                #CityNum:代表城市数量Dist = np.zeros((CityNum,CityNum))        #Dist(i,j):城市i与城市j间的距离#计算距离矩阵for i in range(CityNum):for j in range(CityNum):if i==j:Dist[i,j] = math.infelse:Dist[i,j] = math.sqrt(np.sum((Position[i,:]-Position[j,:])**2))return Position,CityNum,Distdef ResultShow(Min_Path,BestPath,CityNum,string):"""函数名:GetData()函数功能:    从外界读取城市数据并处理输入    无输出    1 Position:各个城市的位置矩阵2 CityNum:城市数量3 Dist:城市间距离矩阵其他说明:无"""    print("基于"+string+"求得的最优路线:")for m in range(CityNum):print(str(BestPath[m])+"—>",end="")print(BestPath[CityNum])print("最优值:"+str(Min_Path))print()def draw(BestPath,Position,title):"""函数名:draw(BestPath,Position,title)函数功能:    通过最优路径将旅行商依次经过的城市在图表上绘制出来输入    1     BestPath:最优路径2    Position:各个城市的位置矩阵3    title:图表的标题输出    无其他说明:无"""plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示plt.rcParams['axes.unicode_minus'] = Falseplt.title(title)plt.plot(Position[BestPath, 0],Position[BestPath, 1], marker='>', mec='r', mfc='w',label=u'路线')plt.legend()  # 让图例生效for i,city in enumerate(Position): plt.text(city[0], city[1], str(i))plt.xlabel('横坐标')plt.ylabel('纵坐标')plt.show()def ant():"""函数名:ant()函数功能:蚁群算法核心"""numant = 25          # 蚂蚁个数numcity = CityNum   # 城市个数alpha = 1           # 信息素重要程度因子rho = 0.1           # 信息素的挥发速度Q = 1iters = 0itermax = 500etatable = 1.0/(Dist+np.diag([1e10]*numcity))       # 启发函数矩阵,表示蚂蚁从城市i转移到矩阵j的期望程度pheromonetable  = np.ones((numcity,numcity))        # 信息素矩阵pathtable = np.zeros((numant,numcity)).astype(int)  # 路径记录表lengthaver = np.zeros(itermax)          # 各代路径的平均长度lengthbest = np.zeros(itermax)          # 各代及其之前遇到的最佳路径长度pathbest = np.zeros((itermax,numcity))  # 各代及其之前遇到的最佳路径while iters < itermax:#  随机产生各个蚂蚁的起点城市if numant <= numcity:   # 城市数比蚂蚁数多pathtable[:,0] = np.random.permutation(range(0,numcity))[:numant]else:                   # 蚂蚁数比城市数多,需要补足pathtable[:numcity,0] = np.random.permutation(range(0,numcity))[:]pathtable[numcity:,0] = np.random.permutation(range(0,numcity))[:numant-numcity]length = np.zeros(numant)       # 计算各个蚂蚁的路径距离for i in range(numant): visiting = pathtable[i,0]         # 当前所在的城市unvisited = set(range(numcity))   # 未访问的城市unvisited.remove(visiting)        # 删除元素for j in range(1,numcity):        # 循环numcity-1次,访问剩余的numcity-1个城市# 每次用轮盘法选择下一个要访问的城市listunvisited = list(unvisited)probtrans = np.zeros(len(listunvisited))for k in range(len(listunvisited)):probtrans[k] = np.power(pheromonetable[visiting][listunvisited[k]],alpha)\*np.power(etatable[visiting][listunvisited[k]],alpha)cumsumprobtrans = (probtrans/sum(probtrans)).cumsum()cumsumprobtrans -= np.random.rand()k = listunvisited[np.where(cumsumprobtrans>0)[0][0]] # 下一个要访问的城市pathtable[i,j] = kunvisited.remove(k)length[i] += Dist[visiting][k]visiting = klength[i] += Dist[visiting][pathtable[i,0]] # 蚂蚁的路径距离包括最后一个城市和第一个城市的距离# 包含所有蚂蚁的一个迭代结束后,统计本次迭代的若干统计参数lengthaver[iters] = length.mean()if iters == 0:lengthbest[iters] = length.min()pathbest[iters] = pathtable[length.argmin()].copy()      else:if length.min() > lengthbest[iters-1]:lengthbest[iters] = lengthbest[iters-1]pathbest[iters] = pathbest[iters-1].copy()else:lengthbest[iters] = length.min()pathbest[iters] = pathtable[length.argmin()].copy()    # 更新信息素changepheromonetable = np.zeros((numcity,numcity))for i in range(numant):for j in range(numcity-1):changepheromonetable[pathtable[i,j]][pathtable[i,j+1]] += Q/length[i]changepheromonetable[pathtable[i,j+1]][pathtable[i,0]] += Q/length[i]pheromonetable = (1-rho)*pheromonetable + changepheromonetable# 迭代次数指示器+1iters += 1 path_tmp=pathbest[-1]BestPath=[]for i in path_tmp:BestPath.append(int(i))BestPath.append(BestPath[0])return BestPath,lengthbest[-1]#########程序入口#########################################
if __name__ == "__main__":Position,CityNum,Dist = GetData("data.txt")start=perf_counter()       #计时开始BestPath,Min_Path = ant()print("运行时间是: {:.5f}s".format(perf_counter()-start))            # 程序计时结束print()ResultShow(Min_Path,BestPath,CityNum,"蚁群算法")draw(BestPath,Position,"轨迹图")

【建模算法】基于蚁群算法求解TSP问题(Python实现)相关推荐

  1. 基于蚁群算法的10个城市TSP问题的最短路径研究(附源码及讲解步骤)

    基于蚁群算法的10个城市TSP问题的最短路径研究 欢迎关注:天际使徒的个人博客 1 蚁群算法 1.1 蚁群算法的流程步骤 这里以TSP问题为例,算法设计的流程如下: 步骤1:对相关参数进行初始化,包括 ...

  2. ​【路径规划】基于蚁群算法求解多式联运路径规划问题matlab源码

    1 简介 随着国际贸易的不断发展和国内外物品流通的速度不断加快,多式联运作为一种先进的运输组织形式不断发展.在运输过程中,合理的路径选择和运输模式选择对多式联运的经营者会带来卓有成效的经济效益,而其中 ...

  3. 【路径规划】基于蚁群算法求解运钞车路径规划VRPSD问题matlab代码

    1 简介 近年来,国内各大城市陆续建立了专业的金融押运企业,为银行网点的现钞运送提供服务.为了实现运钞智能化,降低银行运营成本,需要对银行现钞运送车辆路径规划提供决策支持.而银行运钞车路线规划问题是车 ...

  4. 【本科毕业设计】基于蚁群算法的无人机飞行路径规划

    基于蚁群算法的无人机飞行路径规划 1. 绪论 1.1 选题背景及意义 1.2 研究现状 1.2.1 路径规划的研究现状 2. 四旋翼无人机 2.1 四旋翼无人机简介 2.2 无人机飞行工作原理 2.2 ...

  5. 路由选路java,java基于蚁群算法路由选择可视化动态模拟-开题报告

    <java基于蚁群算法路由选择可视化动态模拟-开题报告>由会员分享,可在线阅读,更多相关<java基于蚁群算法路由选择可视化动态模拟-开题报告(3页珍藏版)>请在人人文库网上搜 ...

  6. 链路状态算法实现Java,JAVA基于蚁群算法路由选择可视化动态模拟(开题报告+任务书+毕业论文+外文翻译+源代码+可执行程序+答辩P...

    JAVA基于蚁群算法路由选择可视化动态模拟(开题报告+任务书+毕业论文+外文翻译+源代码+可执行程序+答辩PPT) 摘 要 路由选择是一种基于网络层的协议,而所有流行的网络层路由选择协议都是基于以下两 ...

  7. 【 无错版】基于蚁群算法的机器人路径规划matlab程序代码实现

    文章目录 1. 按 2. 介绍 3. matlab实现 3.1. 代码 3.2. 效果 1. 按 网上有发的这个算法的错误版的,不知道发的意义何在,是在误人子弟吗???在此对其行为表示强烈的谴责. 错 ...

  8. 【无人机三维路径规划】基于蚁群算法实现无人机三维路径规划含Matlab代码

    ⛄ 内容介绍 随着无人机可执行任务的多样化,航迹规划成为其顺利完成任务的基本前提.针对该问题,提出了基于蚁群算法的无人机航迹规划方法.运用等效地形模拟方法,将作战区域中的敌方威胁.地形障碍等效为山峰, ...

  9. matlab蚁群算法 路径规划,基于蚁群算法的机器人路径规划MATLAB源码

    基于蚁群算法的机器人路径规划MA TLAB源码 使用网格离散化的方法对带有障碍物的环境建模,使用邻接矩阵存储该环境,使得问题转化为蚁群算法寻找最短路径. function [ROUTES,PL,Tau ...

最新文章

  1. 一次SQL查询优化原理分析(900W+数据,从17s到300ms)
  2. Dart 流中的 listen 和 forEach 有什么区别?
  3. jQuery BreakingNews 间歇滚动
  4. 毕业一年多被裁,没有计算机文凭,我在两个月内搞定4份Offer,且收入翻倍
  5. 浅析jQuery中常用的元素查找方法总结
  6. 一次较为完整的原生JavaScript AJAX与Java的前后端数据交互
  7. dedeCMS解决问题:“用户资料尚未通过审核,因此空间禁止访问”?
  8. [5.数据类型] 零基础学python,简单粗暴
  9. 字节(bytes) 二进制序列类型
  10. 黄聪:VS2008的动、静态编译[转]
  11. [Laravel]配置路由小记
  12. win7计算机不显示dvd,win7系统不显示光驱盘符的解决方法
  13. UWB三维定位方式概述
  14. 云计算就业方向有哪些 未来的发展前景怎么样
  15. linux中firewalld之direct rules和rich rules(转发,伪装)
  16. 动态规划之《高楼扔鸡蛋》问题详解 LeetCode 887.鸡蛋掉落
  17. echarts地图设置legend_ECharts 的第 100 个版本!
  18. 重磅精品课程总有一门是你想要找的
  19. Github-谷歌插件gitzip(加速器-不用再忍受几十kb/s的煎熬了)
  20. 45页精华《2022中国建筑行业数字化转型研究报告》出炉(附下载)

热门文章

  1. HTML5 面试题整理
  2. 计算机组装部件推荐,电脑组装的配件有哪些
  3. 满二叉树与完全二叉树
  4. 基于JAVA的教师管理系统设计与开发
  5. win10安装配置ssh服务
  6. Verilog实现的SPI通信协议(主机模式)
  7. 【转】虎扑步行街评论---大开眼界专栏第104期评论。
  8. SAP知道后台配置路径如何查找后台配置的TCODE(后台配置的事务码)
  9. Mol Cell Proteomics. |彭建祥| 人胃肠道间质瘤亚群蛋白质组图谱
  10. 2022年建筑八大员报名时间和条件是什么?甘建二告诉你