流程图
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3f0981edef4e0178060a5f4a64f82ccd.png)
数据集
att48.tsp
关键要素
- 解的编码:实数编码
- 群体初始化:随机最近邻居构造启发式算法生成一个初始满意解,其余随机生成
- 适应度评价函数:总距离的倒数
- 选择:依概率轮赌盘法选择父代
- 交叉:顺序交叉
- 变异:2-opt变异 (父代一定变异,子代依概率变异)
- 相关参数: N=100;Pm=0.02;Maxlter=2000
- 改进:在以上常规遗传算法的基础上,我又添加了局部搜索算法,以保持每代种群质量的优良性,提高对最优解的搜索能力,但降低了搜索的随机性。
代码
import random
import numpy as np
import math
import pandas as pd
import copy
import matplotlib.pyplot as plt
import time
import random
def data_deal(city):
city = np.array(city[0][6:len(city) - 1])
city_name = city.tolist()
chu_li = []
for i in range(0, len(city_name)):
temp = city_name[i].split()
del temp[0]
for x in range(0, 2):
temp[x] = eval(temp[x])
chu_li.append(temp)
return chu_li
a280 = pd.read_csv(r'a280.tsp', encoding='utf-8-sig', header=None)
att48 = pd.read_csv(r'att48.tsp', encoding='utf-8-sig', header=None)
ch150 = pd.read_csv(r'ch150.tsp', encoding='utf-8-sig', header=None)
eil76 = pd.read_csv(r'eil76.tsp', encoding='utf-8-sig', header=None)
lin105 = pd.read_csv(r'lin105.tsp', encoding='utf-8-sig', header=None)
city_location=data_deal(att48)
city_num = [i for i in range(len(city_location))]
city_count=len(city_num)
origin = 0
remain_cities = city_num[:]
remain_cities.remove(origin)
remain_count = city_count - 1
indexs = city_num.remove(origin)
dis =[[0]*city_count for i in range(city_count)]
for i in range(city_count):
for j in range(city_count):
if i != j:
dis[i][j] = math.sqrt((city_location[i][0]-city_location[j][0])**2 + (city_location[i][1]-city_location[j][1])**2)
else:
dis[i][j] = 0
def route_mile_cost(route):
'''
计算路径的里程成本
'''
mile_cost=0+dis[0][route[0]]
for j in range(remain_count-1):
mile_cost+=dis[route[j]][route[j+1]]
mile_cost+=dis[route[remain_count-1]][0]
return mile_cost
def distance(city_a, city_b):
x = city_a[0] - city_b[0]
y = city_a[1] - city_b[1]
dist = (x ** 2 + y ** 2) ** 0.5
return dist
def greedy_initial_route():
temp=city_location[:]
for i in range(0,len(temp)-1):
dis = distance(temp[i], temp[i+1])
for j in range(i+2,len(temp)):
t=distance(temp[i],temp[j])
if t<dis:
dis=t
temp[i+1],temp[j]=temp[j],temp[i+1]
route=[]
for i in temp:
route.append(city_location.index(i))
del route[0]
return route
def selection(population):
'''
选出父代个体
'''
M = population_size
parents = []
for i in range(M):
if random.random() < (1 - i/M):
parents.append(population[i])
return parents
def CPX(parent1,parent2):
'''顺序交叉'''
dot=random.randint(1, city_count-1)
behind=parent2[dot:]
font=[]
for i in parent1:
if i not in behind:
font.append(i)
child=font+behind
return child
'''
交叉繁殖:CX与PX的混合双亲产生两个子代
cycle = []
start = parent1[0]
cycle.append(start)
end = parent2[0]
while end != start:
cycle.append(end)
end = parent2[parent1.index(end)]
child = parent1[:]
cross_points = cycle[:]
if len(cross_points) < 2 :
cross_points = random.sample(parent1,2)
k = 0
for i in range(len(parent1)):
if child[i] in cross_points:
continue
else:
for j in range(k,len(parent2)):
if parent2[j] in cross_points:
continue
else:
child[i] = parent2[j]
k = j + 1
break
return child
'''
def mutation(children,mutation_rate):
'''
子代变异
'''
for e in range(len(children)):
if random.random() < mutation_rate:
i=0
j=0
while(i==j):
i=random.randint(1,remain_count-1)
j=random.randint(1,remain_count-1)
child_new=children[e].copy()
child_new[i:j+1]=list(reversed(child_new[i:j+1]))
children[e]=child_new
return children
def get_best_current(population):
'''
将种群的个体按照里程排序,并返回当前种群中的最优个体及其里程
'''
graded = [[route_mile_cost(x),x] for x in population]
graded = sorted(graded)
population = [x[1] for x in graded]
mean=sum([x[0] for x in graded])/len(population)
return graded[0][0],graded[0][1],population,mean
def find_newpath(path_best):
path_new=[]
for i in range(0,city_count-1):
for j in range(i+1,city_count-1):
path=path_best.copy()
path[i:j+1]=list(reversed(path[i:j+1]))
path_new.append(path)
return path_new
def cal_newpath(dis_mat,path_new):
dis_list=[]
for each in path_new:
t=route_mile_cost(each)
dis_list.append(t)
return dis_list
population_size = 100
mutation_rate = 0.02
def main(iter_count):
population = [greedy_initial_route()]
for i in range(population_size-1):
individual = remain_cities[:]
random.shuffle(individual)
population.append(individual)
mile_cost,result,population,mean = get_best_current(population)
record = [mile_cost]
means=[mean]
iter = 0
while iter < iter_count:
parents = selection(population)
target_count = population_size - len(parents)
children = []
while len(children) < target_count:
parent1,parent2 = random.sample(parents,2)
child1 = CPX(parent1,parent2)
child2 = CPX(parent2,parent1)
children.append(child1)
children.append(child2)
parents = mutation(parents,1)
children = mutation(children,mutation_rate)
population = parents + children
''' 取消注释 并将下方get_best_current的参数改为p_t 此时为遗传+局部搜索
p_t=[]
for i in population:
for j in range(2):#迭代
#寻找全领域新解
path_new=find_newpath(i)
#print(path_new)
#求出所有新解的路径长度
dis_new=cal_newpath(dis,path_new)
# print(dis_new)
#选择路径
dis_best=min(dis_new)#最短距离
path_best=path_new[dis_new.index(dis_best)]#对应的最短路径方案
p_t.append(path_best)
'''
mile_cost,result,population,mean = get_best_current(population)
record.append(mile_cost)
means.append(mean)
iter =iter+1
route = [origin] + result + [origin]
return route,mile_cost,record,means
def fig():
time_start = time.time()
N = 2000
satisfactory_solution,mile_cost,record,means = main(N)
time_end = time.time()
time_cost = time_end - time_start
print('time cost:',time_cost)
print("优化里程成本:%d" %(int(mile_cost)))
print("优化路径:\n",satisfactory_solution)
for i in range(1,len(satisfactory_solution)):
for j in range(i+1,len(satisfactory_solution)):
if satisfactory_solution[i]==satisfactory_solution[j]:
print(i)
print("wrong")
break
X = []
Y = []
for i in satisfactory_solution:
plt.scatter(city_location[i][0], city_location[i][1],color='b')
x = city_location[i][0]
y = city_location[i][1]
X.append(x)
Y.append(y)
plt.plot(X,Y,'-o')
plt.title("satisfactory solution of TS:%d"%(int(mile_cost)))
plt.show()
A = [i for i in range(N+1)]
B = record[:]
C=means[:]
plt.xlim(0,N)
plt.xlabel('进化次数',fontproperties="SimSun")
plt.ylabel('路径里程',fontproperties="SimSun")
plt.title("solution of GA changed with evolution")
plt.plot(A,B,'b-')
plt.plot(A,C,'r-')
plt.legend(["best","average"])
plt.show()
return mile_cost,time_cost
fig()
结果展示
常规的遗传算法
数据集 | 运行时间(s) | 最短距离 | 官方距离 |
---|
att48 | 3 | 34604 | 33533 |
路线图 | 迭代下降图 |
---|
![](https://i-blog.csdnimg.cn/blog_migrate/9a34097c6a42382cd2e3206f396b5edc.png) | ![](https://i-blog.csdnimg.cn/blog_migrate/89127ff8dac2a37652ca39c445fe0d9d.png) |
常规的遗传算法+局部搜索算法
数据集 | 运行时间(s) | 最短距离 | 官方距离 |
---|
att48 | 34 | 33723 | 33533 |
路线图 | 迭代下降图 |
---|
![](https://i-blog.csdnimg.cn/blog_migrate/88b2670c16d540b76969a4a4a0a4b4da.png) | ![](https://i-blog.csdnimg.cn/blog_migrate/b0043c301f7ea454dec023016a9a8584.png) |