(Python)蚁群算法解决旅行商问题(ACO-TSP)

2023-11-09

        蚁群算法又称蚂蚁算法,容易与其他算法相结合,但也存在收敛速度慢,容易陷入局部最优等缺点。

 

# -*- coding: utf-8 -*-
import random
import copy
import time
import sys
import math
import tkinter  # //GUI模块
import threading
from functools import reduce

# 参数
'''
ALPHA:信息启发因子,值越大,则蚂蚁选择之前走过的路径可能性就越大
      ,值越小,则蚁群搜索范围就会减少,容易陷入局部最优
BETA:Beta值越大,蚁群越就容易选择局部较短路径,这时算法收敛速度会
     加快,但是随机性不高,容易得到局部的相对最优
RHO:控制参数,更新信息素矩阵时使用
Q:正常数,信息素计算时使用
'''
(ALPHA, BETA, RHO, Q) = (1.0, 2.0, 0.5, 100.0)
# 城市数,蚁群
(city_num, ant_num) = (50, 50)
distance_x = [
    178, 272, 176, 171, 650, 499, 267, 703, 408, 437, 491, 74, 532,
    416, 626, 42, 271, 359, 163, 508, 229, 576, 147, 560, 35, 714,
    757, 517, 64, 314, 675, 690, 391, 628, 87, 240, 705, 699, 258,
    428, 614, 36, 360, 482, 666, 597, 209, 201, 492, 294]
distance_y = [
    170, 395, 198, 151, 242, 556, 57, 401, 305, 421, 267, 105, 525,
    381, 244, 330, 395, 169, 141, 380, 153, 442, 528, 329, 232, 48,
    498, 265, 343, 120, 165, 50, 433, 63, 491, 275, 348, 222, 288,
    490, 213, 524, 244, 114, 104, 552, 70, 425, 227, 331]
# 城市距离和信息素
distance_graph = [[0.0 for col in range(city_num)] for raw in range(city_num)] # list里有50个list,每个子list里有50个0.0
pheromone_graph = [[1.0 for col in range(city_num)] for raw in range(city_num)]# 大list里套50个小list,小list里初始为50个1.0
print(f"初始化城市距离矩阵:\n{distance_graph}")
print(f"初始化信息素矩阵:\n{pheromone_graph}")

# ----------- 蚂蚁 -----------
class Ant(object):
    # 初始化
    def __init__(self, ID):
        self.ID = ID  # ID
        self.__clean_data()  # 随机初始化出生点

    # 初始数据
    def __clean_data(self):
        self.path = []  # 当前蚂蚁的路径
        self.total_distance = 0.0  # 当前路径的总距离
        self.move_count = 0  # 移动次数
        self.current_city = -1  # 当前停留的城市
        self.open_table_city = [True for i in range(city_num)]  # 探索城市的状态
        # print(self.open_table_city)
        city_index = random.randint(0, city_num - 1)  # 随机初始出生点
        self.current_city = city_index
        self.path.append(city_index)
        self.open_table_city[city_index] = False
        self.move_count = 1

    # 选择下一个城市
    def __choice_next_city(self):
        next_city = -1
        select_citys_prob = [0.0 for i in range(city_num)]  # 存储去下个城市的概率
        total_prob = 0.0    # 所有概率之和,用于轮盘赌选择城市

        # 获取去下一个城市的概率
        for i in range(city_num):
            if self.open_table_city[i]: # 如果这里是true 那就是这个城市还没去过
                try:
                    # 计算概率:与信息素浓度成正比,与距离成反比 pow(x,y)计算x的y次幂
                    select_citys_prob[i] = pow(pheromone_graph[self.current_city][i], ALPHA) * pow(
                        (1.0 / distance_graph[self.current_city][i]), BETA)
                    total_prob += select_citys_prob[i]
                except ZeroDivisionError as e:
                    print('Ant ID: {ID}, current city: {current}, target city: {target}'.format(ID=self.ID,
                                                                                                current=self.current_city,
                                                                                                target=i))
                    sys.exit(1)

        # 轮盘选择城市
        if total_prob > 0.0:
            # 产生一个随机概率,0.0--total_prob
            temp_prob = random.uniform(0.0, total_prob) # 产生的浮点数范围为【a,b】,所以可能为total_prob
            for i in range(city_num):
                if self.open_table_city[i]: #  如果这里是true 那就是这个城市还没去过
                    # 轮次相减
                    temp_prob -= select_citys_prob[i]
                    if temp_prob < 0.0: # 最终结果可能为0
                        next_city = i
                        break

        # 不从概率产生,顺序选择一个未访问城市
        # if next_city == -1:
        #     for i in range(city_num):
        #         if self.open_table_city[i]:
        #             next_city = i
        #             break

        if (next_city == -1):
            next_city = random.randint(0, city_num - 1)
            while ((self.open_table_city[next_city]) == False):  # if==False,说明已经遍历过了
                next_city = random.randint(0, city_num - 1)

        # 返回下一个城市序号
        return next_city

    # 计算路径总距离
    def __cal_total_distance(self):

        temp_distance = 0.0

        for i in range(1, city_num):
            start, end = self.path[i], self.path[i - 1]
            temp_distance += distance_graph[start][end]

        # 回路
        end = self.path[0]  # 最后将end置为原点,回到原点
        temp_distance += distance_graph[start][end]
        self.total_distance = temp_distance

    # 移动操作
    def __move(self, next_city):

        self.path.append(next_city)
        self.open_table_city[next_city] = False
        self.total_distance += distance_graph[self.current_city][next_city]
        self.current_city = next_city
        self.move_count += 1

    # 搜索路径
    def search_path(self):

        # 初始化数据
        self.__clean_data()

        # 搜素路径,遍历完所有城市为止
        while self.move_count < city_num:
            # 移动到下一个城市
            next_city = self.__choice_next_city()
            self.__move(next_city)

        # 计算路径总长度
        self.__cal_total_distance()


# ----------- TSP问题 -----------

class TSP(object):

    def __init__(self, root, width=800, height=600, n=city_num):

        # 创建画布
        self.root = root
        self.width = width
        self.height = height
        # 城市数目初始化为city_num
        self.n = n
        # tkinter.Canvas
        self.canvas = tkinter.Canvas(
            root,
            width=self.width,
            height=self.height,
            bg="#EBEBEB",  # 背景白色
            xscrollincrement=1,
            yscrollincrement=1
        )
        self.canvas.pack(expand=tkinter.YES, fill=tkinter.BOTH)
        self.title("TSP蚁群算法(n:初始化 e:开始搜索 s:停止搜索 q:退出程序)")
        self.__r = 5 # 节点椭圆半径
        self.__lock = threading.RLock()  # 线程锁

        self.__bindEvents()
        self.new()

        # 计算城市之间的距离
        for i in range(city_num):
            for j in range(city_num):
                temp_distance = pow((distance_x[i] - distance_x[j]), 2) + pow((distance_y[i] - distance_y[j]), 2)
                temp_distance = pow(temp_distance, 0.5)
                distance_graph[i][j] = float(int(temp_distance + 0.5))

    # 按键响应程序
    def __bindEvents(self):

        self.root.bind("q", self.quite)  # 退出程序
        self.root.bind("n", self.new)  # 初始化
        self.root.bind("e", self.search_path)  # 开始搜索
        self.root.bind("s", self.stop)  # 停止搜索

    # 更改标题
    def title(self, s):

        self.root.title(s)

    # 初始化
    def new(self, evt=None):

        # 停止线程
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()

        self.clear()  # 清除信息
        self.nodes = []  # 节点坐标
        self.nodes2 = []  # 节点对象

        # 初始化城市节点
        for i in range(len(distance_x)):
            # 在画布上随机初始坐标
            x = distance_x[i]
            y = distance_y[i]
            self.nodes.append((x, y))
            # 生成节点椭圆,半径为self.__r
            node = self.canvas.create_oval(x - self.__r,y - self.__r,
                                           x + self.__r, y + self.__r,
                                           fill="#ff0000",  # 填充红色
                                           outline="#000000",  # 轮廓白色
                                           tags="node",
                                           )
            self.nodes2.append(node)
            # 显示坐标
            self.canvas.create_text(x, y - 10,  # 使用create_text方法在坐标(302,77)处绘制文字
                                    text='(' + str(x) + ',' + str(y) + ')',  # 所绘制文字的内容
                                    fill='black'  # 所绘制文字的颜色为灰色
                                    )

        # 顺序连接城市
        # self.line(range(city_num))

        # 初始城市之间的距离和信息素
        for i in range(city_num):
            for j in range(city_num):
                pheromone_graph[i][j] = 1.0

        self.ants = [Ant(ID) for ID in range(ant_num)]  # 初始蚁群
        self.best_ant = Ant(-1)  # 初始最优解
        self.best_ant.total_distance = 1 << 31  # 初始最大距离
        self.iter = 1  # 初始化迭代次数

    # 将节点按order顺序连线
    def line(self, order):
        # 删除原线
        self.canvas.delete("line")

        def line2(i1, i2):
            p1, p2 = self.nodes[i1], self.nodes[i2]
            self.canvas.create_line(p1, p2, fill="#000000", tags="line")
            return i2

        # order[-1]为初始值
        reduce(line2, order, order[-1])

    # 清除画布
    def clear(self):
        for item in self.canvas.find_all():
            self.canvas.delete(item)

    # 退出程序
    def quite(self, evt):
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()
        self.root.destroy()
        print(u"\n程序已退出...")
        sys.exit()

    # 停止搜索
    def stop(self, evt):
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()

    # 开始搜索
    def search_path(self, evt=None):

        # 开启线程
        self.__lock.acquire()
        self.__running = True
        self.__lock.release()

        while self.__running:
            # 遍历每一只蚂蚁
            for ant in self.ants:
                # 搜索一条路径
                ant.search_path()
                # 与当前最优蚂蚁比较
                if ant.total_distance < self.best_ant.total_distance:
                    # 更新最优解
                    self.best_ant = copy.deepcopy(ant)
            # 更新信息素
            self.__update_pheromone_gragh()
            print(u"迭代次数:", self.iter, u"最佳路径总距离:", int(self.best_ant.total_distance))
            # 连线
            self.line(self.best_ant.path)
            # 设置标题
            self.title("TSP蚁群算法(n:随机初始 e:开始搜索 s:停止搜索 q:退出程序) 迭代次数: %d" % self.iter)
            # 更新画布
            self.canvas.update()
            self.iter += 1

    # 更新信息素
    def __update_pheromone_gragh(self):
        # 获取每只蚂蚁在其路径上留下的信息素
        temp_pheromone = [[0.0 for col in range(city_num)] for raw in range(city_num)]
        for ant in self.ants:
            for i in range(1, city_num):
                start, end = ant.path[i - 1], ant.path[i]
                # 在路径上的每两个相邻城市间留下信息素,与路径总距离反比
                temp_pheromone[start][end] += Q / ant.total_distance
                temp_pheromone[end][start] = temp_pheromone[start][end]

        # 更新所有城市之间的信息素,旧信息素衰减加上新迭代信息素
        for i in range(city_num):
            for j in range(city_num):
                pheromone_graph[i][j] = pheromone_graph[i][j] * RHO + temp_pheromone[i][j]

    # 主循环
    def mainloop(self):
        self.root.mainloop()


# ----------- 程序的入口处 -----------

if __name__ == '__main__':
    TSP(tkinter.Tk()).mainloop()

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(Python)蚁群算法解决旅行商问题(ACO-TSP) 的相关文章

  • 如何并行安装/编译 pip 要求(使 -j 等效)

    我的 pip 要求中有很多软件包需要安装 我想并行处理它们 我知道 例如 如果我想要n并行作业来自make我必须写make j n 是否有满足 pip 要求的等效命令 Thanks 有时 pip 使用 make 来构建依赖项 如果在开始之前
  • 执行不区分大小写的“in”检查并检索原始元素的最简单方法?

    假设 a 有一个字符串列表和一个特定字符串 particular string latitude list Id PRICE LATitude longitude 我想要实现的是执行不区分大小写的检查特定字符串是否在列表中 所以现在我可以这
  • 分类报告 - 精度和 F 分数定义不明确

    我从 sklearn metrics 导入了classification report 当我输入我的np arrays作为参数我收到以下错误 usr local lib python3 6 dist packages sklearn met
  • 在 opencv 中一次性将旋转和平移结合起来

    我有一段用于旋转和平移图像的代码 Point2f pt 0 in rows double angle atan trans c trans b 180 M PI Mat r getRotationMatrix2D pt angle 1 0
  • 如何将魔杖图像对象转换为 numpy 数组(不使用 OpenCV)?

    我正在使用将 pdf 文件转换为图像Wand http docs wand py org en 0 4 4 然后 我使用 ndimage 进行进一步的图像处理 我想直接将 Wand 图像转换为 ndarray 我已经看到答案here htt
  • 读取大文件并制作字典

    我有一个大文件 我需要读取它并从中制作字典 我希望这一切能够尽可能快 然而我的Python代码太慢了 这是一个显示问题的最小示例 首先制作一些假数据 paste lt seq 20000000 lt seq 2 20000001 gt la
  • python解释器自动重启而不返回答案

    调用递归函数时 python解释器会自动重新启动吗 我正在编写一个快速排序算法 并尝试对一个大的数字数组 顺序 10 4 进行排序 但是当我尝试对整个数组进行排序时 python 正在重新启动 即给我 重新启动 并且存储在内存中的所有值 函
  • IndexError:布尔索引与维度 0 上的索引数组不匹配

    在我将 Numpy 更新到 1 13 1 之前 我的代码工作正常 现在我收到以下错误 IndexError boolean index did not match indexed array along dimension 0 dimens
  • 代码终止后保持 matplotlib / pyplot 窗口打开

    我希望 python 绘制一个图 在不阻塞控制流的情况下显示它 并在代码退出后使图保持打开状态 这可能吗 这个以及相关的主题存在于许多其他线程中 见下文 但我无法让情节保持开放且非阻塞 例如 如果我使用pyplot ion before p
  • 组内条件计数

    我想在之后进行条件计数groupby 例如 按列的值分组A 然后计算每组中值出现的频率5出现在列中B 如果我整个过程都这样做DataFrame 只是len df df B 5 所以我希望我能做到df groupby A df B 5 siz
  • 需要Python字长函数示例

    我的家庭作业有点困难 我本来应该编写一个函数 limitWords 将输入限制为 20 个单词 如果输入超过 20 个单词 则将输入截断为仅 20 个单词 我使用 len text split 作为计算单词的方法 因此 20 个或更少的部分
  • 将 Python 列表(JSON 或其他)插入 MySQL 数据库

    所以我在Python中有一堆数组数据 嗯 相反 我有一个清单 我试图将此数组存储到 MySQL 数据库中的单个单元格中 我尝试使用 JSON 来序列化我的数据 但也许我不明白 JSON 是如何工作的 因此 在连接到我的数据库后 我尝试了上游
  • [matplotlib]:理解“set_ydata”方法

    我试图了解如何使用 set ydata 方法 我在 matplotlib 网页上找到了很多示例 但我只找到了 set ydata 被 淹没 在大型且难以理解的代码中的代码 我想要一个简短且易于理解的代码来帮助我理解 set ydata 的工
  • 张量流 - 向量中的前 k 个值到二进制向量

    假设我有一个带有值的向量 0 4 1 2 8 7 0 2 如何获得前 k 个值的二进制向量 k 3 0 1 0 0 1 1 0 0 in 张量流 TensorFlow 的tf math top k https www tensorflow
  • 如何通过不规则索引获取子张量?

    我想通过不规则索引获得子张量 这是我的问题 Input tensor 2x8x10x1 Batch x Height x Width x Channel index Height 0 1 4 5 index Width 0 1 4 5 8
  • 使用 Django 添加额外 \\ 字符的 JSON 编码

    我正在尝试创建一个函数 将包含消息和 Django 模型实例的字典转换为 JSON 然后我可以将其传回客户端 例如 我在 models py 中定义了模型 Test from django db import models class Te
  • Django Rest框架Json解析

    我想解析传入的POSTdjangoviews py 文件中的数据 发布数据 number 17386372 data banana apple grapes 这是我尝试读取上述传入数据的方法request views py class Fr
  • df.style.apply 在显示中居中显示多索引值

    当我跑步时 import pandas as pd from IPython display import display df pd DataFrame a index pd MultiIndex from product 0 1 3 c
  • 使用缓存时计算“页面浏览量”或“点击量”

    我有一个叫做show board 在其中 除其他外 我增加了一个字段Board views每次运行时加 1 以计算页面浏览量 问题是当我在该视图上使用 cache page 装饰器时 Board views仅在每次生成新的缓存视图时才会增加
  • 与仅调用依赖函数/类相比,在 FastAPI 中使用 Depends 有哪些优点?

    FastAPI 提供了way https fastapi tiangolo com tutorial dependencies 通过其自己的依赖关系解析机制来管理依赖关系 例如数据库连接 它类似于一个pytest夹具系统 简而言之 您在函数

随机推荐

  • 未完成---VBA的键盘事件相关

    试了几个地方 有的有些 有的问题很多 1 workbook open时调用 不好用 Private Sub Workbook Open Load UserForm6 UserForm6 Show Application OnKey a wb
  • WordPress(4)关于网站的背景图片更换

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 更改的位置 1 红色区域是要更换的随机的图片 二 替换图片位置 三 开启随机数量 四 结束 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智
  • Java 访问权限控制

    使用访问权限控制的原因 使用户不要触碰到那些不该触碰的部分 类库设计者可以更改类的内部工作模式 而不必担心整体程序造成影响 访问权限修饰词 Java具有三种访问权限修饰词 public private protected 划分出了四种访问权
  • 使用Django完成一个系统(上)

    文章目录 可重用注册登录系统 1 思考 2 搭建项目环境 3 设计数据库模型 4 路由 视图函数及模板的框架搭建 5 前端界面设计与优化 6 完善登录的视图函数 7 session会话与登录的视图函数 可重用注册登录系统 1 思考 需求分析
  • UE 4.19 安卓平台配置和测试

    以前使用UE4打包一个很简单的场景都要几百兆 最近据说这几个版本UE4对移动平台的大小进行了较大的优化 测试一下 附按照环境打包 解压后直接在项目中指定即可 链接 https pan baidu com s 1tAfMjY s56ehjud
  • c语言中两种常见代码编写错误,“写入位置 0x00000000 时发生访问冲突”和“语法错误 : 缺少“;”(在“{”的前面)”

    编程工作者在编程的时候 由于编程不够细心经常出现这样或那样的错误 今天 我在这里说下我所遇到的错误 如下面这个代码就出现了文章标题中的俩个错误 define CRT SECURE NO DEPRECATE include
  • Linux Capabilities

    Linux Capabilities是一种细粒度的权限管理机制 用于将root用户的特权划分为具体的功能集 它允许将部分root特权授予非root进程 可以在shell中运行 man capabilities 将显示capability m
  • 格式化数据库字段驼峰式

    public static String format String name if name contains String split name split name split 0 for int m 1 m lt split len
  • pyautogui问题解决方案记录(因为使用了:pyautogui.locateCenterOnScreen(img, confidence=0.9))

    本人环境 win10 1909 Python 3 9 13 不想多余看 只想直接解决 直接安装下面的库 pip install pyautogui pip install pillow pip install opencv python 我
  • 服务器如何发挥最好的性能,一篇文章告诉你怎么发挥固态硬盘最大性能

    对于使用固态硬盘相信大多数玩家对于其性能是否良好没有一个客观上的认知 今天就给大家详细介绍下如何让自己的固态硬盘保持良好的性能状态 从东芝TR200看固态硬盘满盘性能与读取延迟 固态硬盘的性能与很多因素有关 其中空间使用情况也会给固态硬盘的
  • Windows 下设置自定义域名解析到指定 IP

    Windows 下设置自定义域名解析到指定 IP 一 操作步骤 1 定位到 host文件 2 编辑 host文件属性 3 添加解析文件 域名 4 重启电脑 5 在命令行中测试域名即可 导言 记录一下 Windows下设置域名解析到指定 IP
  • 二次封装一个比较通用的elementUI表单

    一下代码仅添加input和select 如有需要还可以加入单选多选日期等
  • cocos2dx linux eclipse,win7下在eclipse中搭建cocos2d-x开发环境

    1 eclipse下载 进入eclipse官网下载 Eclipse standard 4 4 下载页面 3 Android SDK下载 http developer android com sdk index html 也可以下捆绑的 ec
  • Android快速编译调试framework.jar等系统包的步骤

    引言 前段时间在调试android9的系统源码 修改完了framework service等路径下的源码后 编译生成system img 但这种方式需要把system img从服务器上Down下来 再让设备进入fastboot模式 线刷 调
  • Selenium+Pytest自动化测试框架实战

    前言 selenium自动化 pytest测试框架 本章你需要 一定的python基础 至少明白类与对象 封装继承 一定的selenium基础 本篇不讲selenium 不会的可以自己去看selenium中文翻译网 一 测试框架简介 测试框
  • vue2实现百度地图定位

    用的是vue2的地图定位插件 https dafrok github io vue baidu map zh control city list 1 首先肯定是先下载了 npm i vue baidu map S 2 下载完记得全局引入 在
  • Qt 插入Label到指定位置

    QLabel label new QLabel this label gt setFrameStyle QFrame Panel QFrame Sunken label gt setText first line nsecond line
  • [C++]中介者模式

    中介者模式 Mediator Pattern 是用来降低多个对象和类之间的通信复杂性 这种模式提供了一个中介类 该类通常处理不同类之间的通信 并支持松耦合 使代码易于维护 中介者模式属于行为型模式 github源码路径 https gith
  • VSCode配置C语言环境(完整版)

    基本步骤 要在VSCode中配置C语言环境 我们首先可能要一个VSCode 废话 所以先下载安装一个VSCode 然后肯定需要相关插件 因为VSCode不能直接拿来写C 然后任何语言的程序在运行前都需要编译 那还需要一个编译器 很可惜VSC
  • (Python)蚁群算法解决旅行商问题(ACO-TSP)

    蚁群算法又称蚂蚁算法 容易与其他算法相结合 但也存在收敛速度慢 容易陷入局部最优等缺点 coding utf 8 import random import copy import time import sys import math im