基于禁忌搜索算法(TS)的TSP(Python实现)

news2024/11/19 18:35:19

        本篇文章是博主在最化优学习、人工智能等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在最优化算法

       最优化算法(1)---基于禁忌搜索算法(TS)的TSP(Python实现)》

基于禁忌搜索算法(TS)的TSP(Python实现)

目录

基于禁忌搜索算法(TS)的TSP(Python实现)

1.项目介绍       

2.程序代码

3.运行结果


1.项目介绍       

        基于禁忌搜索算法(TS)的TSP(Traveling Salesman Problem,旅行商问题),涉及一种用于解决TSP的优化方法。TSP是一个经典的组合优化问题,目标是寻找一条最短路径,使得旅行商可以访问每个城市恰好一次并返回起点城市。

        TS算法作为一种启发式优化算法,在TSP求解中具有广泛的应用。相较于传统的穷举或贪婪算法,TS算法通过引入禁忌列表和邻域结构来更全面地探索解空间,从而更有可能找到较为优秀的近似最优解。

        禁忌搜索算法从一个初始解开始,在每次迭代中根据邻域结构生成新的解,并根据目标函数对其质量进行评估。若新解优于当前最优解且未出现在禁忌列表中,则接受该解作为当前最优解;否则,寻找下一个最佳候选解。同时,禁忌列表会记录一段时间内禁止选择的解,以避免陷入循环或重复访问相似解的情况。

        在TSP问题上,邻域结构通常包括交换两个城市的位置、翻转子路径等操作,而目标函数则是路径长度。禁忌搜索通过不断迭代搜索和更新禁忌列表,逐步改进当前路径,直至满足结束条件为止。

在基于TS算法求解TSP问题时,禁忌搜索的核心思想包括以下几个方面:

  1. 禁忌列表:记录已经探索过的路径或解,以避免下一步重复探索相同的路径或解。
  2. 邻域结构:定义了TSP解空间中可行解之间的相邻关系,如通过交换、插入等操作生成新的解。
  3. 目标函数:通常是TSP问题中路径长度的计算,用于评估每个解的质量。

TS算法求解TSP的基本步骤包括:

  • 初始化:随机生成初始路径
  • 迭代搜索:根据邻域结构和目标函数,通过禁忌搜索不断调整路径,并更新禁忌列表,记录当前最优路径
  • 终止条件:达到预设的迭代次数或满足特定条件时结束搜索,返回最优路径

        通过利用TS算法求解TSP问题,可以有效地寻找到较为优秀的旅行路线,虽不能保证找到全局最优解,但通常能获得接近最优解的结果。


2.程序代码

""""
题目:基于禁忌搜索算法的TSP
作者:Rainbook
最终修改时间:2023.12.30
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
import numpy as np

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 使用微软雅黑字体
plt.rcParams['axes.unicode_minus'] = False  # 处理负号显示异常


# 计算路径距离,即评价函数
def calFitness(line, dis_matrix):
    dis_sum = 0
    dis = 0
    for i in range(len(line)):
        if i < len(line) - 1:
            dis = dis_matrix.loc[line[i], line[i + 1]]  # 计算距离
            dis_sum = dis_sum + dis
        else:
            dis = dis_matrix.loc[line[i], line[0]]
            dis_sum = dis_sum + dis
    return round(dis_sum, 1)


def traversal_search(line, dis_matrix, tabu_list):
    # 邻域随机遍历搜索
    traversal = 0  # 搜索次数
    traversal_list = []  # 存储局部搜索生成的解,也充当局部禁忌表
    traversal_value = []  # 存储局部解对应路径距离
    while traversal <= traversalMax:
        pos1, pos2 = random.randint(0, len(line) - 1), random.randint(0, len(line) - 1)  # 交换点
        # 复制当前路径,并交换生成新路径
        new_line = line.copy()
        new_line[pos1], new_line[pos2] = new_line[pos2], new_line[pos1]
        new_value = calFitness(new_line, dis_matrix)  # 当前路径距离
        # 新生成路径不在全局禁忌表和局部禁忌表中,为有效搜索,否则继续搜索
        if (new_line not in traversal_list) & (new_line not in tabu_list):
            traversal_list.append(new_line)
            traversal_value.append(new_value)
            traversal += 1

    return min(traversal_value), traversal_list[traversal_value.index(min(traversal_value))]


def greedy(CityCoordinates, dis_matrix):
    '''贪婪策略构造初始解'''
    # 出来dis_matrix
    dis_matrix = dis_matrix.astype('float64')
    for i in range(len(CityCoordinates)): dis_matrix.loc[i, i] = math.pow(10, 10)
    line = []  # 初始化
    now_city = random.randint(0, len(CityCoordinates) - 1)  # 随机生成出发城市
    line.append(now_city)  # 添加当前城市到路径
    dis_matrix.loc[:, now_city] = math.pow(10, 10)  # 更新距离矩阵,已经过城市不再被取出
    for i in range(len(CityCoordinates) - 1):
        next_city = dis_matrix.loc[now_city, :].idxmin()  # 距离最近的城市
        line.append(next_city)  # 添加进路径
        dis_matrix.loc[:, next_city] = math.pow(10, 10)  # 更新距离矩阵
        now_city = next_city  # 更新当前城市

    return line


# 画路径图
def draw_path(line, CityCoordinates):
    x, y = [], []
    for i in line:
        Coordinate = CityCoordinates[i]
        x.append(Coordinate[0])
        y.append(Coordinate[1])

    for j in range(len(line) - 1):
        plt.quiver(x[j], y[j], x[j + 1] - x[j], y[j + 1] - y[j], color='r', width=0.005, angles='xy', scale=1,
                   scale_units='xy')
    plt.quiver(x[-1], y[-1], x[0] - x[-1], y[0] - y[-1], color='r', width=0.005, angles='xy', scale=1,
               scale_units='xy')
    plt.title('基于禁忌搜索算法的TSP')
    # plt.figure()
    # plt.plot(x, y,color='r', alpha=0.8, linewidth=0.8)
    # plt.xlabel('x')
    # plt.ylabel('y')
    plt.show()


if __name__ == '__main__':
    # 随机生成城市信息
    nCity = 50
    CityCoordinates = np.random.uniform(0, 2000, [nCity, 2])  # uniform()生成nCity个二维数组,数值范围是0到2000

    # 参数设置
    CityNum = nCity  # 城市数量
    MinCoordinate = 0  # 二维坐标最小值
    MaxCoordinate = 101  # 二维坐标最大值
    tabu_limit = 50  # 禁忌长度,该值应小于(CityNum*(CityNum-1)/2)
    iterMax = 200  # 迭代次数
    traversalMax = 100  # 每一代局部搜索次数
    tabu_list = []  # 禁忌表
    tabu_time = []  # 禁忌次数
    best_value = math.pow(10, 10)  # 较大的初始值,存储最优解
    best_line = []  # 存储最优路径

    # 计算城市之间的距离
    dis_matrix = pd.DataFrame(data=None, columns=range(len(CityCoordinates)), index=range(len(CityCoordinates)))
    for i in range(len(CityCoordinates)):
        xi, yi = CityCoordinates[i][0], CityCoordinates[i][1]
        for j in range(len(CityCoordinates)):
            xj, yj = CityCoordinates[j][0], CityCoordinates[j][1]
            dis_matrix.iloc[i, j] = round(math.sqrt((xi - xj) ** 2 + (yi - yj) ** 2), 2)

    # 贪婪构造
    line = greedy(CityCoordinates, dis_matrix)
    value = calFitness(line, dis_matrix)  # 初始路径距离

    # 存储当前最优
    best_value, best_line = value, line
    best_value_list = []
    best_value_list.append(best_value)
    # 更新禁忌表
    tabu_list.append(line)
    tabu_time.append(tabu_limit)

    itera = 0
    while itera <= iterMax:
        new_value, new_line = traversal_search(line, dis_matrix, tabu_list)
        if new_value < best_value:  # 优于最优解
            best_value, best_line = new_value, new_line  # 更新最优解
            best_value_list.append(best_value)
            print('第%d次:当前优解为' % (itera+1))
            print(best_line)
        line, value = new_line, new_value  # 更新当前解

        # 更新禁忌表
        tabu_time = [x - 1 for x in tabu_time]
        if 0 in tabu_time:
            tabu_list.remove(tabu_list[tabu_time.index(0)])
            tabu_time.remove(0)

        tabu_list.append(line)
        tabu_time.append(tabu_limit)
        itera += 1

    # 路径顺序
    print("-------最优解为:")
    print(best_line)
    # 画路径图
    draw_path(best_line, CityCoordinates)

3.运行结果


        参考资料来源:CSDN、百度搜索、维基百科等

        文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者关注VX公众号:Rain21321,联系作者。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1500692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MRI基础--k空间

k空间定义 k空间是表示 MR 图像中空间频率的数字数组。 k空间物理意义 k 空间的单元通常显示在主轴 kx 和 ky 的矩形网格上。 k 空间的 kx 和 ky 轴对应于图像的水平 (x) 和垂直 (y) 轴。然而,k 轴表示 x 和 y 方向上的空间频率而不是位置。 k 空间中的各个点 (kx,ky) 与图像…

Python 映射函数map()详解

一、映射函数定义 它用于对容器中的元素进行映射&#xff08;或变换&#xff09; 二、映射函数语法 map(function, iterable) function&#xff1a;一个提供变换规则的函数&#xff0c;返回变换之后的元素iterable&#xff1a;一个或多个序列&#xff08;可迭代对象&#xff09…

005-事件捕获、冒泡事件委托

事件捕获、冒泡&事件委托 1、事件捕获与冒泡2、事件冒泡示例3、阻止事件冒泡4、阻止事件默认行为5、事件委托6、事件委托优点 1、事件捕获与冒泡 2、事件冒泡示例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /…

【嵌入式高级C语言】9:万能型链表懒人手册

文章目录 序言单向不循环链表拼图框架搭建 - Necessary功能拼图块1 创建链表头信息结构体 - Necessary2 链表头部插入 - Optional3 链表的遍历 - Optional4 链表的销毁 - Necessary5 链表头信息结构体销毁 - Necessary6 获取链表中节点的个数 - Optional7 链表尾部插入 - Optio…

【软件测试面试】银行项目测试面试题+答案(一)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 面试题&#xff1…

如何做代币分析:以 ARB 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;ARB 代币仪表板 &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关的数据…

Vue2里,利用原生js input的 type=“file“时,获取上传成功后的文件名及文件内容。下载文件到本地

功能场景:现在有个上传下载文件的功能,不需要调后端接口,因为需求是不需要将文件存到数据库里。如下图,是上传成功的场景: 这里限制上传accept类型为pem, 这里主要用到了input的change事件,如果没上传文件则提醒上传文件后再下载,下载功能主要是运用创建a元素,传入blo…

go语言-k8s宿主信息采集运维脚本

背景 由于工作需要&#xff0c;需要采集k8s集群中的宿主相关信息&#xff0c;包括cpu,memory,lvm,标签等信息。通常作为SRE会主选shell或python脚本来实现。但最近我们团队主流开发语言已经切换到golang.所以本次尝试用go语言来写写运维脚本。 实现流程图 代码实现 package m…

移掉 K 位数字(LeetCode 402)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路4.1 暴力法4.2 贪心 单调栈 参考文献 1.问题描述 给你一个以字符串表示的非负整数 num 和一个整数 k&#xff0c;移除这个数中的 k 位数字&#xff0c;使得剩下的整数最小。请你以字符串形式返回这个最小的整数。 示例 1 …

【产品测试】Bug报告的四个元素,你知道吗?

前言 由于任何由人编写的程序都不可避免的存在着不符合测试需求的错误&#xff0c;也就是bug。因此需要一个方法来跟踪、分析和展示那些测试活动&#xff0c;避免偏离最小。这种方法称之为错误跟踪系统。它主要是有效的管理缺陷&#xff0c;实现以下作用&#xff1a; 1)减少由…

YOLOX论文解读

paper&#xff1a;YOLOX: Exceeding YOLO Series in 2021 official implementation&#xff1a;https://github.com/Megvii-BaseDetection/YOLOX 本文的创新点 本文在YOLOv3的基础上进行了一些改进&#xff1a;包括将检测头进行解耦的decoupled head、从anchor-based转为anc…

经典定时任务结构设计:时间轮(Timing Wheel)案例和实现原理

1、直接上案例 import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; import io.netty.util.TimerTask; import lombok.extern.log4j.Log4j2;import java.util.concurrent.TimeUnit;/*** ClassName Test* Author will* Date 2024/3/8 16:31* Version 1.0.1*…

【PCIe】TLP结构与配置空间

&#x1f525;博客主页&#xff1a;PannLZ 文章目录 PCIe TLP结构PCIe配置空间和地址空间 PCIe TLP结构 TLP 主要由3个部分组成&#xff1a; Header 、 数据(可选&#xff0c;取决于具体的TLP 类 型 ) 和 ECRC (End to End CRC, 可选)。TLP 都始于发送端的事务层&#xff0c;终…

网络仿真(二)

时延和丢包率 网络中的节点之间时延&#xff08;延迟&#xff09;和丢包率是衡量网络性能的两个关键指标。 时延&#xff08;延迟&#xff09;&#xff1a;时延是指数据在网络中从一个节点传输到另一个节点所需的时间。这包括处理时延&#xff08;数据在节点处理的时间&#x…

ENVI必须会教程—Sentinel-2数据的读取与波段组合加载

实验2&#xff1a;读取Sentinel-2影像 目的&#xff1a;了解Sentinel-2影像读取方法&#xff0c;熟悉各波段及组合 过程&#xff1a; ①读取数据&#xff1a;在标题栏选择“文件”选项&#xff0c;点击“打开为”&#xff0c;选择“光学传感器”&#xff0c;由于哨兵2号数据…

Java后端八股笔记

Java后端八股笔记 Redis八股 上两种都有可能导致脏数据 所以使用两次删除缓存的技术&#xff0c;延时是因为数据库有主从问题需要更新&#xff0c;无法达到完全的强一致性&#xff0c;只能达到控制一致性。 一般放入缓存中的数据都是读多写少的数据 业务逻辑代码&#x1f44…

#stm32外设总结电容触摸按键

BS8116A-3 IRQ 外部中断请求 NMOS输出内部上拉 SCL SDA IIC通信接口 VDD 供电电压2.2-5.5V Ct电容: 0~25 pF 电容越大灵敏度越低 1、 软件使用流程 初始化 将IIC的两个引脚初始化为复用开漏模式 按键引脚设置上拉输入 下降沿触发外部中断 void KEY_Init(void) {//uint8_t …

音视频学习笔记——实现PCM和H264合成MP4功能

本文主要记录实现PCM和H264合成MP4功能的整个框架&#xff0c;各个模块中FFmpeg的api使用流程&#xff0c;便于后续学习和复盘。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感兴趣…

2024最新算法:冠豪猪优化算法(Crested Porcupine Optimizer,CPO)求解23个基准函数(提供MATLAB代码)

一、冠豪猪优化算法 冠豪猪优化算法(Crested Porcupine Optimizer&#xff0c;CPO)由Mohamed Abdel-Basset等人于2024年提出&#xff0c;该算法模拟冠豪猪的四种不同保护机制&#xff1a;视觉、听觉、气味和物理攻击。第一和第二防御技术&#xff08;视觉和听觉&#xff09;反…

安装nexus + 部署私有maven仓库

安装nexus 部署私有maven仓库 文章目录 安装nexus 部署私有maven仓库1.下载2.解压3.修改配置文件4.启动5.访问6.查看默认密码7.创建私库8.修改代码配置文件9.在maven 的setting.xml中配置私库的账号密码10.运行manve 【deploy】命令测试11.maven项目引用私库12. 重新加载mave…