本文参考了以下文章:(也建议直接去看他们的文章,我这里只是提供了python版本的代码和初学者需要的一些代码注释)
模拟退火算法理论:https://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html
模拟退火算法实例:https://blog.csdn.net/baimafujinji/article/details/52573630
关于模拟退火算法之前只看理论,到头来还是一知半解,而今抬手编程,发现很简单的一个实例就能让你记得更牢,何乐而不为?
源码是C++的,我看懂了之后通过重新编写python程序来达到熟练理解的目的;另外,我在实例的基础上添加了详细注释,便于初学者理解。
'''
该代码通过模拟退火算法来寻找旅行商问题(TSP)的近似最优解
'''
import math
import random
import time
T = 5000 # 初始温度
DELTA = 0.8 # 温度衰减率
# 内循环内的两个限制
ILOOP = 500 # 内循环最大循环次数
LIMIT = 200 # 内循环中失败的最大次数
# 外循环的两个限制
OLOOP = 10 # 外循环最大循环次数
EPS = 1e-8 # 达到最低温度时退出循环
class Path:
def __init__(self, cities=[], len=0):
self.cities = cities
self.len = len
# 计算两点距离
def distance(x, y):
return math.sqrt(pow(x[0] - y[0], 2) + pow(x[1] - y[1], 2))
# 构建距离矩阵
def getDistMatrix(a, n):
distMatrix = [[0] * n for i in range(n)]
for i in range(n - 1):
for j in range(i + 1, n):
distMatrix[i][j] = distMatrix[j][i] = distance(a[i], a[j])
# for i in range(n):
# for j in range(n):
# print(distMatrix[i][j]," ")
# print()
return distMatrix
# 初始化路径
def get_init_path(a, n, distMatrix):
initPath = Path() # 路径
for i in range(n - 1):
initPath.cities.append(i)
initPath.len = initPath.len + distMatrix[i][i + 1]
initPath.cities.append(n - 1)
print(initPath.cities, ": ", initPath.len)
return initPath
# 随机产生新路径
def get_next_path(n, curPath):
newPath = Path()
newPath.cities = curPath.cities
# 随机取两个不同随机数
random.seed(time.time())
x = random.randint(0, n - 1)
random.seed(time.time())
y = random.randint(0, n - 1)
while x == y:
x = random.randint(0, n - 1)
y = random.randint(0, n - 1)
# 采用两点位置交换法产生新路径
temp = newPath.cities[x]
newPath.cities[x] = newPath.cities[y]
newPath.cities[y] = temp
for i in range(n - 1):
newPath.len = newPath.len + distMatrix[newPath.cities[i]][newPath.cities[i + 1]]
return newPath
# 搜索
def search(n, curPath, T):
loop_L = 0
bad_num = 0
while True:
loop_L = loop_L + 1
for i in range(ILOOP):
nextPath = get_next_path(n, curPath)
dE = nextPath.len - curPath.len
if dE < 0:
curPath = nextPath
print(curPath.cities, ": ", curPath.len)
bad_num = 0
bad_bad_num = 0
else:
p = math.exp((-1) * dE / T)
r = random.random()
if p > r:
curPath = nextPath
print(curPath.cities, ": ", curPath.len)
# 不论随机取到到的较差解有没有被采纳,都要记一次失败
bad_num = bad_num + 1
# 如果失败次数超过限制时,则应该退出
if bad_num > LIMIT:
bad_bad_num = bad_bad_num + 1
break
if bad_bad_num > OLOOP or T < EPS:
break
# 每次外循环结束就更新一下温度值
T = T * DELTA
print(curPath.cities, ": ", curPath.len)
return curPath.len
# 打印结果
if __name__ == '__main__':
# 输入
a = [[1, 0], [0, 6], [2, 3], [5, 4], [6, 1], [7, 5], [8, 2]]
n = len(a)
# 构建距离矩阵
distMatrix = getDistMatrix(a, n)
# 初始化路径
initPath = get_init_path(a, n, distMatrix)
# 搜索
minLen = search(n, initPath, T)
# 打印结果
print("所以最短路径是", minLen)