遗传算法求解TSP问题

实验三 遗传算法求解TSP问题

一、实验目的:

熟悉和掌握遗传算法的原理流程和编码策略,并利用遗传求解函数优化问题,理解求解流程并测试主要参数对结果的影响。

二、实验原理:

遗传算法的基本思想正是基于模仿生物界遗传学的遗传过程。它把问题的参数用基因代表,把问题的解用染色体代表(在计算机里用二进制码表示),从而得到一个由具有不同染色体的个体组成的群体。这个群体在问题特定的环境里生存竞争,适者有最好的机会生存和产生后代。后代随机化地继承了父代的最好特征,并也在生存环境的控制支配下继续这一过程.群体的染色体都将逐渐适应环境,不断进化,最后收敛到一族最适应环境的类似个体,即得到问题最优的解

三、实验条件:

  • Python版本:Python 3及以上
  • 所需要的依赖包:random、copy、matplotlib
  • 可采用的软件:vscode

四、实验内容:

利用遗传算法求解函数最大值

五、实验步骤:

代码实现步骤

  • 导入所需的库:numpy、random、matplotlib.pyplot 和 copy。
  • 定义城市坐标矩阵 City_Map,表示各个城市的经纬度。
  • 定义 DNA_SIZE,表示编码长度,即城市数量。
  • 定义种群大小 POP_SIZE,表示每个个体包含的城市顺序。
  • 定义交叉率 CROSS_RATE,表示两个个体进行交叉的概率。
  • 定义变异率 MUTA_RATE,表示基因突变的概率。
  • 定义迭代次数 Iterations,表示算法运行的轮数。
  • 定义计算距离的函数 distance(DNA),输入为一个表示城市顺序的列表,输出为该顺序对应的总距离。
  • 定义计算适应度的函数 getfitness(pop),输入为一个种群列表,输出为每个个体的适应度值。适应度用距离的倒数表示。
  • 定义选择函数 select(pop, fitness),输入为一个种群列表和对应的适应度值,输出为经过选择后的新种群。选择过程采用赌轮盘形式,适应度越大的个体被选中的概率越大。
  • 定义变异函数 mutation(DNA, MUTA_RATE),输入为一个表示城市顺序的列表和一个变异率,输出为经过变异后的新列表。变异过程随机选择一个位置,然后与另一个位置交换基因。
  • 定义交叉变异函数 crossmuta(pop, CROSS_RATE),输入为一个种群列表和交叉率,输出为经过交叉变异后的新种群。交叉过程选取两个父代个体,通过部分匹配交叉生成子代个体。
  • 定义打印结果的函数 print_info(pop),输入为一个种群列表,输出为最优解的信息,包括最优基因型和最短距离。同时绘制地图和路线图。
  • 在主循环中,首先生成初始种群 pop,然后进行选择、交叉、变异操作,并保存每代的最优个体到 best_dis 列表中。迭代 N 代后,打印最优解信息和逐代最小距离。
  • 绘制迭代过程中的最小距离曲线图。

流程图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行代码,查看输出结果

  • 图一:最优基因型、最短距离

  • 图二:旅行商路径

  • 图三:逐步迭代最短距离

源程序

import numpy as np
import random
import matplotlib.pyplot as plt
import copy
#各个城市的坐标

City_Map = [[106.54,29.59]

,[91.11,29.97]

,[87.68,43.77]

,[106.27,38.47]

,[111.65,40.82]

,[108.33,22.84]

,[126.63,45.75]

,[125.35,43.88]

,[123.38,41.8]

,[114.48,38.03]

,[112.53,37.87]

,[101.74,36.56]

,[117,36.65]

,[113.6,34.76]

,[118.78,32.04]

,[117.27,31.86]]

City_Map = 100 * np.random.rand(20, 2)#随机产生 20 个城市
DNA_SIZE = len(City_Map) #编码长度
POP_SIZE = 200 #种群大小
CROSS_RATE = 0.6 #交叉率
MUTA_RATE = 0.2 #变异率
Iterations = 1000 #迭代次数
def distance(DNA):#根据 DNA 的路线计算距离
dis = 0
temp = City_Map[DNA[0]]
for i in DNA[1:]:
dis = dis + ((City_Map[i][0]-temp[0])**2+(City_Map[i][1]-temp[1])**2)**0.5
temp = City_Map[i]
return dis+((temp[0]-City_Map[DNA[0]][0])**2+(temp[1]-City_Map[DNA[0]][1])**2)**0.5
def getfitness(pop):#计算种群适应度,这里适应度用距离的倒数表示
temp = []
for i in range(len(pop)):
temp.append(1/(distance(pop[i])))
return temp-np.min(temp)
def select(pop, fitness): # 根据适应度选择,以赌轮盘的形式,适应度越大的个体被选中的概率越大
s = fitness.sum()
temp = np.random.choice(np.arange(len(pop)), size=POP_SIZE, replace=True,p=(fitness/s))
p = []
for i in temp:
p.append(pop[i])
return p
def mutation(DNA, MUTA_RATE):#进行变异
if np.random.rand() < MUTA_RATE: #以 MUTA_RATE 的概率进行变异
mutate_point1 = np.random.randint(0, DNA_SIZE)#随机产生一个实数,代表要变异基因的位置
mutate_point2 = np.random.randint(0,DNA_SIZE)#随机产生一个实数,代表要变异基因的位置
while(mutate_point1 == mutate_point2):#保证 2 个所选位置不相等
mutate_point2 = np.random.randint(0,DNA_SIZE)
DNA[mutate_point1],DNA[mutate_point2] = DNA[mutate_point2],DNA[mutate_point1]
#2 个所选位置进行互换
def crossmuta(pop, CROSS_RATE):#交叉变异
new_pop = []
for i in range(len(pop)):#遍历种群中的每一个个体,将该个体作为父代
n=np.random.rand()
if n>=CROSS_RATE:#大于交叉概率时不发生变异,该子代直接进入下一代
temp = pop[i].copy()
new_pop.append(temp)
if n<CROSS_RATE:#小于交叉概率时发生变异
list1 = pop[i].copy()
list2 = pop[np.random.randint(POP_SIZE)].copy()#选取种群中另一个个体进行交叉
status = True
while status:#产生 2 个不相等的节点,中间部分作为交叉段,采用部分匹配交叉
k1 = random.randint(0, len(list1) - 1)
k2 = random.randint(0, len(list2) - 1)
if k1 < k2:
status = False
k11 = k1
fragment1 = list1[k1: k2]
fragment2 = list2[k1: k2]
list1[k1: k2] = fragment2
list2[k1: k2] = fragment1
del list1[k1: k2]
left1 = list1
offspring1 = []
for pos in left1:
if pos in fragment2:
pos = fragment1[fragment2.index(pos)]
while pos in fragment2:
pos = fragment1[fragment2.index(pos)]
offspring1.append(pos)
continue
offspring1.append(pos)
for i in range(0, len(fragment2)):
offspring1.insert(k11, fragment2[i])
k11 += 1
temp = offspring1.copy()
mutation(temp,MUTA_RATE)
new_pop.append(temp)#把部分匹配交叉后形成的合法个体加入到下一代种群
return new_pop
def print_info(pop):#用于输出结果
fitness = getfitness(pop)
maxfitness = np.argmax(fitness)#得到种群中最大适应度个体的索引
#打印结果
print(“最优的基因型:”, pop[maxfitness])
print(“最短距离:”,distance(pop[maxfitness]))
#按最优结果顺序把地图上的点加入到 best_map 列表中
best_map = []
for i in pop[maxfitness]:
best_map.append(City_Map[i])
best_map.append(City_Map[pop[maxfitness][0]])
X = np.array((best_map))[:,0]
Y = np.array((best_map))[:,1]
#绘制地图以及路线
plt.figure()
plt.rcParams[‘font.sans-serif’] = [‘SimHei’]
plt.scatter(X,Y)
for dot in range(len(X)-1):
plt.annotate(pop[maxfitness][dot],xy=(X[dot],Y[dot]),xytext = (X[dot],Y[dot]))
plt.annotate(‘start’,xy=(X[0],Y[0]),xytext = (X[0]+1,Y[0]))
plt.plot(X,Y)
if name == “main”:#主循环
#生成初代种群 pop
pop = []
list1 = list(range(DNA_SIZE))
for i in range(POP_SIZE):
random.shuffle(list1)
l = list1.copy()
pop.append(l)
best_dis= []
#进行选择,交叉,变异,并把每代的最优个体保存在 best_dis 中
for i in range(Iterations): # 迭代 N 代
pop = crossmuta(pop, CROSS_RATE)
fitness = getfitness(pop)
maxfitness = np.argmax(fitness)
best_dis.append(distance(pop[maxfitness]))
pop = select(pop, fitness) # 选择生成新的种群
print_info(pop)#打印信息
print(‘逐代的最小距离:’,best_dis)
#画图
plt.figure()
plt.plot(range(Iterations),best_dis)
plt.show()
plt.close()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值