欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

禁忌搜索算法实现31个城市的TSP旅行商问题

程序员文章站 2022-05-20 20:24:54
...

研究生专业课上的一门实验,当初做的时候其实迷迷糊糊的,参照了一些网友的思想完成了该篇实验。
但本次是在全邻域内搜索,当初实现局部邻域搜索的时候,结果并不是那么理想,所以有朋友有好的想法可以一起分享分享。

#-*-coding:gb2312-*-
# 禁忌搜索算法实现31个城市TSP问题
import random
import math
import matplotlib.pyplot as plt

global m, best, tl, ca  # m 城市个数 best全局最优  tl初始禁忌长度  ca最大候选集的个数
global time, spe  # time 迭代次数, spe特赦值
best = float('Inf')  # 全局最优初始化为正无穷
m = 31
tl = int(round(math.sqrt(m*(m-1)/2), 0))
spe = 10
time = 250
ca = 200
tabu = [[0] * (m) for i in range(m)]  # 声明并初始化禁忌表
best_way = [0] * m
now_way = [0] * m  # best_way 最优解  now_way当前解
dis = [[0] * (m) for i in range(m)]  # 使用邻接矩阵存储两城市之间的距离
p = []  # 存放31个城市的坐标

class no:  # 该类表示每个点的坐标
    def __init__(self, x, y):
        self.x = x
        self.y = y

def draw(t,re):  # 该函数用于描绘解t的路线图以及迭代过程图
    # 路线图
    x = [0] * (m + 1)
    y = [0] * (m + 1)
    for i in range(m):
        x[i] = p[t[i]].x
        y[i] = p[t[i]].y
    x[m] = p[t[0]].x
    y[m] = p[t[0]].y
    plt.plot(x, y, color='r', marker='*')
    plt.show()

    # 迭代过程图
    A = [i for i in range(time)] # 横坐标
    B = re[:]  # 纵坐标
    plt.xlim(0,time)
    plt.xlabel("迭代次数",fontproperties="SimSun")
    plt.ylabel("路径长度",fontproperties="SimSun")
    plt.title("适应度进化曲线",fontproperties="SimSun")
    plt.plot(A, B, '-')
    plt.show()



def mycol():  # 城市坐标输入
    coordinate = [[1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535], [3326, 1556],
                  [3238, 1229], [4196, 1004], [4312, 790], [4386, 570], [3007, 1970], [2562, 1756],
                  [2788, 1491], [2381, 1676], [1332, 695], [3715, 1678], [3918, 2179], [4061, 2370],
                  [3780, 2212], [3676, 2578], [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2367],
                  [3394, 2643], [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826], [2370, 2975]
                  ]
    for i in coordinate:
        p.append(no(i[0], i[1]))


def get_dis(a, b):  # 返回a,b两城市的直线距离
    return math.sqrt((p[a].x - p[b].x) * (p[a].x - p[b].x) + (p[a].y - p[b].y) * (p[a].y - p[b].y))


def get_value(t):  # 计算解t的路线长度
    ans = 0.0
    for i in range(1, m):
        ans += dis[t[i]][t[i - 1]]
    ans += dis[t[0]][t[m - 1]]
    return ans


def cop(a, b):  # 把b数组的值赋值a数组
    for i in range(m):
        a[i] = b[i]


def rand(g):  # 随机生成初始解
    vis = [0] * m
    on = 0
    while on < m:
        te = random.randint(0, m - 1)  # 产生一个代表城市序号的随机数
        if (vis[te] == 0):  # 如果当前选出的随机数其对应位置的值为1代表已被选中,则跳过;否则,将当前数加入初始解中
            vis[te] = 1
            g[on] = te
            on += 1

def greedy(g):
    # 使用贪婪算法产生初始解,从第一个城市CR出发,寻找与其直线距离最短的城市NR并标记,令CR=dis_index,然后继续寻找与CR距离最近的城市并标记,直到所有的城市被标记完
    # 初始解的第一个出发城市由随机数产生
    #temp = [random.randint(0, m-1)]
    temp = [0]  # 固定从第一个城市出发,产生的解唯一
    count = 1
    CR = temp[0]
    while count < m:
        distance = [0] * m  # 存储CR与其他城市的距离
        cop(distance, dis[CR])
        distance.sort()  # 对当前城市与其他城市的距离进行排序
        distance = distance[1:]  # 排除掉为0的城市到自己的距离
        dis_index = dis[CR].index(distance[0])  # 将距离最短城市的下标找出
        i = 1
        while dis_index in temp:  # 如果当前距离最短的城市已在初始解里,则找次小的
            dis_index = dis[CR].index(distance[i])
            i += 1
        temp.append(dis_index)
        count += 1
        CR = dis_index
    cop(g, temp)


def init():  # 初始化函数
    global best
    for i in range(m):
        for j in range(m):
            if i == j:
                continue
            value = get_dis(i, j)
            dis[i][j] = value  # 初始化所有城市之间的直线距离
            dis[j][i] = value

    #rand(now_way)  # 生成初始解作为当前解
    greedy(now_way)
    now = get_value(now_way)  # 计算初始解的长度
    cop(best_way, now_way)  # 将当前的初始解及其长度赋给最佳解
    best = now


def slove():  # 迭代函数
    global best, now_way
    temp = [0] * m  # 中间变量记录交换结果
    a = 0
    b = 0  # 记录交换城市下标
    ob_way = [0] * m
    cop(ob_way, now_way)
    ob_value = get_value(now_way)  # 暂存邻域最优解
    for i in range(1, m):  # 搜索所有邻域
        for j in range(1, m):
            if (i + j >= m): break
            if (i == j): continue
            cop(temp, now_way)
            temp[i], temp[i + j] = temp[i + j], temp[i]  # 交换
            value = get_value(temp)
            if (value <= best and tabu[i][i + j] < spe):  # 如果优于全局最优且禁忌长度小于特赦值
                cop(best_way, temp)
                best = value
                a = i
                b = i + j  # 更新全局最优且接受新解
                cop(ob_way, temp)
                ob_value = value
            elif (tabu[i][i + j] == 0 and value < ob_value):  # 如果优于邻域中的最优解则暂存邻域最优解
                cop(ob_way, temp)
                ob_value = value
                a = i
                b = i + j  # 接受新解的坐标
    cop(now_way, ob_way)  # 更新当前解
    for i in range(m):  # 更新禁忌表
        for j in range(m):
            if (tabu[i][j] > 0):
                tabu[i][j] -= 1
    tabu[a][b] = tl  # a,b被选中,重置a,b两个交换城市的禁忌值
    return best  # 每次迭代完毕后,返回最优路径长度


# *************************入口函数*************************
if __name__ == "__main__":
    record = [0] * time  # record每次产生的最优解的路径长度
    mycol()  # 数据输入
    init()  # 数据初始化

    for i in range(time):  # 控制迭代次数
        value = slove()
        record[i] = value / pow(10, 4)
    print("路线总长度:", round(best, 3))  # 打印最优解距离保留三位小数
    print("具体路线:", best_way)  # 打印路线,以序列表示
    draw(best_way, record)  # 路线图与迭代过程图

随机产生初始解:
路线总长度: 17090.424
具体路线: [0, 28, 10, 5, 4, 22, 24, 25, 27, 26, 30, 29, 23, 17, 2, 21, 20, 19, 18, 16, 15, 3, 7, 8, 9, 1, 6, 12, 11, 13, 14]
禁忌搜索算法实现31个城市的TSP旅行商问题
禁忌搜索算法实现31个城市的TSP旅行商问题
贪婪算法产生初始解
路线总长度: 16561.835
具体路线: [6, 5, 4, 3, 15, 22, 10, 11, 13, 14, 0, 28, 30, 29, 26, 27, 25, 24, 19, 23, 18, 16, 17, 20, 21, 2, 7, 8, 9, 1, 12]
禁忌搜索算法实现31个城市的TSP旅行商问题
禁忌搜索算法实现31个城市的TSP旅行商问题

相关标签: python 数学建模