如何让蚂蚁用python画出爱心(蚁群算法)

跑蚁群算法时,我使用tkinter库让最优路径可视化,闲心思突然就冒了出来,如何让蚂蚁画出爱心呢?只需要适当调整节点坐标即可,

话不多说,展示代码

import random
import numpy as np
import copy
import tkinter
from functools import reduce

# ----------------------------------------- #
# 参数设置
# ALPHA 信息素启发因子。其值越大,蚂蚁选择前面蚂蚁走的路径的可能性就越大
# BETA  期望启发因子。其值越大,容易选择局部较短路径,算法收敛速度越快,但易陷入局部最优
# RHO   信息素挥发系数。较大时,导致仅被第一次或者少数蚂蚁经过的路径上的信息素量挥发的过快
# Q     第K只蚂蚁释放的信息素总含量
# ----------------------------------------- #

t = np.linspace(0, 2 * np.pi, 50)
# 每个城市的x和y坐标
distance_x =[int(16 * np.sin(ti)**3) for ti in t ]
distance_y =[-int(13 * np.cos(ti) - 5 * np.cos(2*ti) - 2 * np.cos(3*ti) - np.cos(4*ti)) for ti in t ]
ALPHA = 1.0
BETA = 2.0
RHO = 0.5
Q = 100.0
city_num = len(distance_x)  # 城市数量
ant_num = 50  # 蚂蚁数量




# 50个城市两两之间路径上的距离和信息素浓度,初始化
distance_graph = [[0.0 for col in range(city_num)] for raw in range(city_num)]
pheromone_graph = [[1.0 for col in range(city_num)] for raw in range(city_num)]

# ----------------------------------------- #
# 蚁群算法-城市选择
# ----------------------------------------- #

class Ant(object):  # 每只蚂蚁的属性
    def __init__(self, ID):
        self.ID = ID  # 每只蚂蚁的编号
        self.__clean_data()  # 初始化出生点
    
    #(1)数据初始化
    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)]  # 探索城市的状态,True可以探索
        
        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  # 初始时的移动计数

    #(2)选择下一个城
    def __choice_next_city(self):
        next_city = -1
        select_citys_probs = [0.0 for i in range(city_num)]
        total_prob = 0.0

        for i in range(city_num):
            if self.open_table_city[i] is True:
                dis = distance_graph[self.current_city][i]
                phe = pheromone_graph[self.current_city][i]
                
                # 添加小值以避免除以零
                if dis == 0:
                    dis = 1e-10  # 小的常数值

                select_citys_probs[i] = pow(phe, ALPHA) * pow(1/dis, BETA)
                total_prob += select_citys_probs[i]

        if total_prob > 0.0:
            temp_prob = random.uniform(0.0, total_prob)
            for i in range(city_num):
                if self.open_table_city[i]:
                    temp_prob -= select_citys_probs[i]
                    if temp_prob < 0.0:
                        next_city = i
                        break

        if next_city == -1:
            next_city = random.randint(0, city_num-1)
            while self.open_table_city[next_city] == False:
                next_city = random.randint(0, city_num-1)

        return next_city

    

    #(3)计算路径总距离
    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]  # 起点变终点
        temp_distance += distance_graph[start][end]  # 这里的start是最后一个节点的索引
        # 走过的总距离
        self.total_distance = temp_distance

    #(4)移动
    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  # 移动次数
    
    #(5)搜索路径
    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()

# ----------------------------------------- #
# 旅行商问题
# ----------------------------------------- #

class TSP(object):
    def __init__(self, root, width=800, height=600, n=city_num):
        # 创建画布
        self.width = width
        self.height = height
        self.n = n  # 城市数目
        # 画布
        self.canvas = tkinter.Canvas(
            root,  # 主窗口
            width = self.width,
            height = self.height,
            bg = "#EBEBEB",  # 白色背景
        )

        self.r = 5  # 圆形节点的半径
        # 显示画布
        self.canvas.pack()
        self.new()  # 初始化

        # 计算两两城市之间的距离,构造距离矩阵
        for i in range(city_num):
            for j in range(city_num):
                # 计算城市i和j之间的距离
                temp_dis = pow((distance_x[i]-distance_x[j]), 2) + pow((distance_y[i]-distance_y[j]), 2)
                temp_dis = pow(temp_dis, 0.5)
                # 距离矩阵向上取整数
                distance_graph[i][j] = float(int(temp_dis + 0.5))

    # 初始化
    def new(self, env=None):
        self.__running = False
        self.clear()  # 清除信息
        self.nodes = []  # 节点的坐标
        self.nodes2 = []  # 节点的对象属性

        # 遍历所有城市生成节点信息
        for i in range(len(distance_x)):
            # 初始化每个节点的坐标
            x = distance_x[i]*15+400
            y = distance_y[i]*15+300
            self.nodes.append((x,y))
            
            # 生成节点信息
            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,
                text=f'({str(x)}, {str(y)})',
                fill='black')
        
        # 初始化所有城市之间的信息素
        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(ID=-1)  # 初始化最优解
        self.best_ant.total_distance = 1 << 31  # 2147483648
        self.iter = 1  # 初始化迭代次数

    # 清除画布
    def clear(self):
        for item in self.canvas.find_all():  # 获取画布上所有对象的ID
            self.canvas.delete(item)  # 删除所有对象

    # 绘制节点之间的连线
    def line(self, order):
        self.canvas.delete('line')  # 删除原线条tags='line'
        # 直线绘制函数
        def draw_line(i1, i2):  # 城市节点的索引
            p1, p2 = self.nodes[i1], self.nodes[i2]
            self.canvas.create_line(p1, p2, fill='#000000', tags = "line")
            return i2  # 下一次线段的起点就是本次线段的终点
        # 按顺序绘制两两节点之间的连线, 为了构成闭环,从最后一个点开始画
        reduce(draw_line, order, order[-1])

    # 开始搜索
    def search_path(self, env=None):
        self.__running = True

        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_graph()
            print(f'iter:{self.iter}, dis:{self.best_ant.total_distance}')
            # 绘制最佳蚂蚁走过的路径, 每只蚂蚁走过的城市索引
            self.line(self.best_ant.path)
            # 更新画布
            self.canvas.update()
            self.iter += 1

    # 更新信息素
    def __update_pheromone_graph(self):
        # 初始化蚂蚁在两两城市间的信息素, 50行50列
        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]

# ----------------------------------------- #
# 主循环
# ----------------------------------------- #

if __name__ == '__main__':

    tsp = TSP(tkinter.Tk())  # 实例化
    tsp.search_path()  # 路径搜索

代码还是有很大优化空间的,比如它会一直迭代,需要手动关闭tk窗口,可以写一段n次迭代后路径不更新则destroy,

还有效率有待提升,如若最优路径不更新则幕布不刷新,可以极大提升效率

运行后图形展示:

 

似乎,只要目前是最优解,那ta一定是爱你的

以下是使用 Python 实现蚁群算法蚂蚁移动动画过程的示例代码: ```python import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation # 定义蚂蚁的数量、城市数量和迭代次数 num_ants = 10 num_cities = 20 num_iterations = 100 # 定义城市的坐标 cities = np.random.rand(num_cities, 2) # 计算城市之间的距离 distances = np.zeros((num_cities, num_cities)) for i in range(num_cities): for j in range(num_cities): distances[i, j] = np.sqrt((cities[i, 0] - cities[j, 0]) ** 2 + (cities[i, 1] - cities[j, 1]) ** 2) # 初始化信息素矩阵 pheromones = np.ones((num_cities, num_cities)) # 定义蚂蚁类 class Ant: def __init__(self, start_city): self.current_city = start_city self.visited_cities = [start_city] self.path_length = 0 def choose_next_city(self): # 计算当前城市与其他未访问城市之间的信息素和距离的乘积 unvisited_cities = [city for city in range(num_cities) if city not in self.visited_cities] product = np.zeros(len(unvisited_cities)) for i, city in enumerate(unvisited_cities): product[i] = pheromones[self.current_city, city] ** 0.5 * (1 / distances[self.current_city, city]) # 根据概率选择下一个城市 probabilities = product / np.sum(product) next_city = np.random.choice(unvisited_cities, p=probabilities) # 更新路径长度和已访问城市列表 self.path_length += distances[self.current_city, next_city] self.current_city = next_city self.visited_cities.append(next_city) # 定义蚂蚁群类 class AntColony: def __init__(self): self.ants = [Ant(start_city=np.random.randint(num_cities)) for i in range(num_ants)] def update_pheromones(self): # 计算每只蚂蚁留下的信息素 delta_pheromones = np.zeros((num_cities, num_cities)) for ant in self.ants: for i in range(len(ant.visited_cities) - 1): current_city = ant.visited_cities[i] next_city = ant.visited_cities[i+1] delta_pheromones[current_city, next_city] += 1 / ant.path_length # 更新信息素矩阵 pheromones *= 0.5 pheromones += delta_pheromones def run(self): # 迭代指定次数 for i in range(num_iterations): # 每只蚂蚁移动一步 for ant in self.ants: ant.choose_next_city() # 更新信息素 self.update_pheromones() # 重置所有蚂蚁的状态 for ant in self.ants: ant.current_city = np.random.randint(num_cities) ant.visited_cities = [ant.current_city] ant.path_length = 0 def get_best_path(self): # 找到最短路径 best_ant = self.ants[0] for ant in self.ants: if ant.path_length < best_ant.path_length: best_ant = ant return best_ant.visited_cities, best_ant.path_length # 定义动画函数 def animate(i): ax.clear() ax.set_xlim(0, 1) ax.set_ylim(0, 1) ax.set_title('Iteration {}'.format(i)) # 运行蚂蚁算法 colony = AntColony() colony.run() # 绘制城市 for j in range(num_cities): ax.plot(cities[j, 0], cities[j, 1], 'bo') # 绘制路径 path, path_length = colony.get_best_path() for j in range(len(path) - 1): ax.plot([cities[path[j], 0], cities[path[j+1], 0]], [cities[path[j], 1], cities[path[j+1], 1]], 'r-') # 显示路径长度 ax.text(0.1, 0.9, 'Path length: {:.2f}'.format(path_length), transform=ax.transAxes) # 创建动画 fig, ax = plt.subplots() ani = animation.FuncAnimation(fig, animate, frames=num_iterations, interval=500) plt.show() ``` 在运行该代码时,会生成一个动画,展示蚂蚁在城市之间移动的过程,并在每次迭代后绘制最佳路径。在动画的右上角,会显示当前迭代次数和最佳路径的长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值