解的形式设置为一个排列
每次改变操作就是交换其中的两个位置的数字
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()