Python 模拟退火算法求解tsp问题

解的形式设置为一个排列

每次改变操作就是交换其中的两个位置的数字

import numpy as np
import random
import matplotlib.pyplot as plt

dis = []
with open('dis17.txt', encoding='utf8', mode='r')  as f:
    for line in f.readlines():
        row = []
        for i in line.strip().split(' '):
            if i.strip() != '':
                row.append(float(i.strip()))
        dis.append(row)

# dis = [
#     [0.00, 24.04, 68.37, 37.66, 58.81, 75.77, 65.20, 57.44, 59.37, 18.61],
#     [24.04, 0.00, 89.58, 57.41, 82.04, 95.54, 59.86, 78.53, 73.57, 16.23],
#     [68.37, 89.58, 0.00, 69.97, 18.91, 11.62, 86.73, 11.05, 34.42, 75.40],
#     [37.66, 57.41, 69.97, 0.00, 52.75, 80.83, 101.03, 61.86, 78.96, 56.26],
#     [58.81, 82.04, 18.91, 52.75, 0.00, 30.52, 92.05, 16.56, 45.24, 69.97],
#     [75.77, 95.54, 11.62, 80.83, 30.52, 0.00, 85.08, 19.42, 31.47, 80.50],
#     [65.20, 59.86, 86.73, 101.03, 92.05, 85.08, 0.00, 78.57, 53.61, 48.83],
#     [57.44, 78.53, 11.05, 61.86, 16.56, 19.42, 78.57, 0.00, 28.99, 64.41],
#     [59.37, 73.57, 34.42, 78.96, 45.24, 31.47, 53.61, 28.99, 0.00, 57.41],
#     [18.61, 16.23, 75.40, 56.26, 69.97, 80.50, 48.83, 64.41, 57.41, 0.00],
# ]

#233
dis = [[0, 84, 90, 68, 62, 78, 77, 100, 55], [32, 0, 44, 67, 55, 21, 82, 83, 9], [4, 37, 0, 28, 65, 15, 17, 3, 10],
           [98, 96, 55, 0, 86, 34, 22, 58, 95], [87, 67, 7, 12, 0, 19, 30, 88, 77], [29, 12, 59, 9, 58, 0, 27, 23, 39],
           [57, 60, 97, 79, 100, 51, 0, 81, 88], [90, 56, 38, 60, 17, 42, 98, 0, 76],
           [28, 55, 94, 88, 91, 23, 35, 55, 0]]
def inputfun(path):
    d = sum([dis[path[i]][path[i + 1]]
             for i in range(len(path) - 1)] + [dis[path[-1]][path[0]]])
    return d


def swap(path):
    m, n = random.randint(0, len(dis) - 1), random.randint(0, len(dis) - 1)
    t = path[m]
    path[m] = path[n]
    path[n] = t


def moni():
    initT = 999  # 初始温度
    minT = 1  # 温度下限
    iterL = 1000  # 每个T值的迭代次数
    delta = 0.95  # 温度衰减系数
    k = 1

    initx = list(range(len(dis)))
    random.shuffle(initx)
    nowt = initT
    # 模拟退火算法寻找最小值过程
    while nowt > minT:
        # iterL = 10 ** (4 - len(str(int(nowt))))
        if nowt < 100:
            iterL = 10000
        for i in np.arange(1, iterL, 1):
            funVal = inputfun(initx)
            xnew = initx.copy()

            if nowt > 300:
                swap(xnew)
            swap(xnew)

            funnew = inputfun(xnew)
            res = funnew - funVal

            # print(funnew)
            if res < 0:
                initx = xnew
            else:
                p = np.exp(-res / (k * nowt))
                if np.random.rand() < p:
                    initx = xnew

        nowt = nowt * delta

    print("最优解:", initx)
    print("最优值:", inputfun(initx))


for i in range(1000):
    moni()

也可以使用实数数组作为解的结构

解的变化是每次交换实数,其实和排列是一样的

也可以随机给某个位置赋值随机数,但是会改变解的结构改变比较大,因为使用实数数组每个位置的实数大小都会影响其他位置的实数,最后影响解的结构

[0.1,0.2,0.3,0.4] --> [0.5,0.2,0.3,0.4]

[1,2,3,4] --> [4,1,2,3]

改变一个位置后会对整体有影响

import numpy as np
import random
import matplotlib.pyplot as plt

dis = []
with open('dis48.txt', encoding='utf8', mode='r')  as f:
    for line in f.readlines():
        row = []
        for i in line.strip().split(' '):
            if i.strip() != '':
                row.append(float(i.strip()))
        dis.append(row)
 

def inputfun(path):
    b = sorted([(i, index) for index, i in enumerate(path)])
    path = [i[1] for i in b]
    d = sum([dis[path[i]][path[i + 1]]
             for i in range(len(path) - 1)] + [dis[path[-1]][path[0]]])
    return d


def moni():
    initT = 999  # 初始温度
    minT = 1  # 温度下限
    iterL = 1000  # 每个T值的迭代次数
    delta = 0.95  # 温度衰减系数
    k = 1

    initx = [random.random() for _ in range(len(dis))]
    nowt = initT
    # 模拟退火算法寻找最小值过程
    while nowt > minT:
        # iterL = 10 ** (4 - len(str(int(nowt))))
        # if nowt < 100:
        #     iterL = 10000
        for i in np.arange(1, iterL, 1):
            funVal = inputfun(initx)
            xnew = initx.copy()

            pos = random.randint(0, len(dis) - 1)
            xnew[pos] = random.random()
            funnew = inputfun(xnew)
            res = funnew - funVal

            # print(funnew)
            if res < 0:
                initx = xnew
            else:
                p = np.exp(-res / (k * nowt))
                if np.random.rand() < p:
                    initx = xnew

        nowt = nowt * delta

    # print("最优解:", initx)
    print("最优值:", inputfun(initx))


for i in range(1000):
    moni()

猜你喜欢

转载自my.oschina.net/ahaoboy/blog/1823327
今日推荐