模拟蚁群陷入局部最优求调
查看原帖
模拟蚁群陷入局部最优求调
1379306
Furinaaaa楼主2024/7/8 23:08

初学模拟蚁群,自己的编译器上把迭代次数和蚂蚁数量调得很大,第五个测试点也是稳定的132而不是130,猜测陷入局部最优,求大佬改进

#模拟蚁群算法的python实现

#假设解决旅行商问题

import random

#创造地图
class City :
    def __init__(self , id ) :
        #城市的编号
        self.id = id
        #字典,记录到每个点的距离,初始为空
        self.distance = {}
        #字典,记录到每个城市路径的初始信息素浓度
        self.way_infor = {}

    #增加一条边
    def add_point ( self , to_id , far , init_infor_value ) :
        self.distance[to_id] = far
        #初始化到to的信息素浓度
        self.way_infor[to_id] = init_infor_value

    #查询到某地的距离
    def get_distance ( self , destination_id ) :
        return self.distance[destination_id]

    #查询到某地的路径的信息素浓度
    def get_infor_value ( self , to_id ) :
        return self.way_infor[to_id]

    #增加一条路径上的信息素浓度
    #p为信息素挥发率
    def add_infor ( self , to_id , infor_value  ) :
        #增加
        self.way_infor[to_id] = self.way_infor[to_id] + infor_value



#创造蚂蚁类
class Ant :
    def __init__(self, start, n):
        # 记录蚂蚁目前、最新到达的点,初始为给定的一个起点
        # start是一个City类
        self.start = start
        # 记录蚂蚁移动的路径,初始为0
        self.way = 0
        # 初始化一个字典,下标1<= i <= n ,初始值为0,表示都没访问过
        self.city_dic = {i: 0 for i in range(1, n + 1, 1)}
        #将起点标记成已访问
        self.city_dic[start.id] = 1
        #记录经过的所有城市的编号
        self.went_list = []
        self.went_list.append(start.id)
        #存储基础的信息素
        self.carry_infor = 0

    # 访问一个城市
    # 注意,需要输入一个城市编号,而不是城市类
    def __visited(self, city_id):
        self.city_dic[city_id] = 1

    # 查询一个节点是不是已经访问过了
    def __is_visited_or_not(self, city_id):
        if self.city_dic[city_id] == 1:
            return 1
        return 0

    # 记录是不是每个节点都访问了,是的话返回1,即TRUE,否则返回0,即FALSE
    def __all_visited(self):
        for city_id in self.city_dic:
            if self.city_dic[city_id] == 0:
                return 0
        return 1

    #到一个城市
    #to是一个city类
    def go_to ( self , to ) :
        #增加蚂蚁走过的距离
        self.way = self.way + self.start.get_distance( to.id )
        #更新起点
        self.start = to
        #标记为已走过
        self.__visited( to.id )
        #加入走过的路径
        self.went_list.append( to.id )

    #根据信息素浓度和能见度,随机决定走哪一条路
    #k1是信息素浓度参数,k2是能见度参数
    #init_start记录最开始的出发地的城市编号
    #返回要走的那个路的编号
    def choose ( self , k1 , k2 , init_start ) :

        #先找到所有可以到达的目的地
        to_ids = []
        #遍历从start出发能到达的所有节点
        #destination是City.id,是城市编号,是一个值
        for destination in self.start.distance :
            #能到达起点,并且所有节点都走到了
            if (destination == init_start) and (self.__all_visited() == 1) :
                self.way = self.way + self.start.get_distance ( init_start )
                #返回-1,表示已经到达目标了
                return -1
            #正常情况,走过的节点就不走
            #没走过的才走
            if self.__is_visited_or_not( destination ) == 0 :
                #没走过,加入可能走的路径
                to_ids.append(destination)
        #如果只有一条路,后面就不用讨论了
        #返回对应的编号
        if len(to_ids) == 1 :
            return to_ids[0]
        #不止一个
        #遍历所有能走的路,计算其概率权重
        #字典,存储概率权重
        p_dic = {}
        #记录概率权重总和
        p_sum = 0
        for to_id in to_ids :
            #获取信息素浓度
            information = self.start.get_infor_value (  to_id )
            #获取能见度,即距离的倒数
            nengjiandu = 1 / self.start.get_distance( to_id )
            p_dic[to_id] = ( information ** k1 ) * ( nengjiandu ** k2 )
            p_sum += p_dic[to_id]

        #计算每个点的概率
        l = []
        k = random.random()
        for to_id in to_ids :
            lx = []
            lx.append(to_id)
            lx.append( p_dic[to_id] / p_sum )
            l.append(lx)
        l.sort( key = lambda x : x[1] )
        #更新为F(X)型的概率分布函数
        for i in range ( 1 , len(l) , 1 ) :
            l[i][1] = l[i][1] + l[i-1][1]
        #找到对应概率的
        for i in l :
            if i[1] >= k :
                return i[0]


#基础信息素设置为n
n = int ( input() )
BASE_INFORMATION = n
zhengfa_rate = 0.75
#每次的蚂蚁数量
ant_army = 55
#记录答案
ans = 999999999
#创建城市字典
city_list = {}
for i in range ( 1 , n + 1 , 1 ) :
    a_city = City(i)
    l = list(map ( int  , input().split() ) )
    for u in range ( 1 , n + 1 , 1 ) :
        x = l[u-1]
        if u == i :
            continue
        a_city.add_point( u , x , n / ant_army )
    city_list[i] = a_city

#派蚂蚁
#假设从1号村庄开始
for _ in range ( 100 ) :
    #对每一个周期
    #生成ant_army只蚂蚁
    #记录每一只蚂蚁
    ant_list = []
    for z in range ( ant_army ) :
        q = Ant( city_list[1] , n )
        ant_list.append(q)

    #对于每一只蚂蚁
    for i in range ( ant_army ) :
        #一直走,直到到达目的地
        while ( 1 ) :
            #找到下一个去处
            to = ant_list[i].choose( 1 , 1 , 1 )
            #找不到,全找完了,结束
            if to == -1 :
                break
            #访问
            ant_list[i].go_to( city_list[to] )
        #比较,看看是不是路径更短
        if ant_list[i].way < ans :
            ans = ant_list[i].way
        #记录这只蚂蚁对信息素的贡献
        ant_list[i].carry_infor = BASE_INFORMATION / ant_list[i].way

    #全部蚂蚁都走完了,更新信息素
    #所有路径先蒸发
    for i in range ( 1 , n + 1 , 1 ) :
        for u in city_list[i].distance :
            city_list[i].way_infor[u] = city_list[i].way_infor[u] * ( 1 - zhengfa_rate )

    #增加
    for i in range ( ant_army ) :
        #对每只蚂蚁
        ant = ant_list[i]
        for u in range ( n - 1 ) :
            #对每条路径,增加信息素
            #注意,增加是双向的
            city_id1 = ant.went_list[u]
            city_id2 = ant.went_list[u+1]
            city_list[city_id1].add_infor( city_id2 , ant.carry_infor )
            city_list[city_id2].add_infor(city_id1, ant.carry_infor)
#输出答案

print( ans )
2024/7/8 23:08
加载中...