遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。
import random
import math
import numpy as np
import matplotlib.pyplot as plt
class GA(object):
def __init__(self, num_city, num_total, iteration, data):
self.num_city = num_city
self.num_total = num_total
self.scores = []
self.iteration = iteration
self.location = data
self.ga_choose_ratio = 0.2
self.mutate_ratio = 0.05
# fruits中存每一个个体是下标的list
self.dis_mat = self.compute_dis_mat(num_city, data)
self.fruits = self.greedy_init(self.dis_mat,num_total,num_city)
# 显示初始化后的最佳路径
scores = self.compute_adp(self.fruits)
sort_index = np.argsort(-scores)
init_best = self.fruits[sort_index[0]]
init_best = self.location[init_best]
# 存储每个iteration的结果,画出收敛图
self.iter_x = [0]
self.iter_y = [1. / scores[sort_index[0]]]
def random_init(self, num_total, num_city):
tmp = [x for x in range(num_city)]
result = []
for i in range(num_total):
random.shuffle(tmp)
result.append(tmp.copy())
return result
def greedy_init(self, dis_mat, num_total, num_city):
start_index = 0
result = []
for i in range(num_total):
rest = [x for x in range(0, num_city)]
# 所有起始点都已经生成了
if start_index >= num_city:
start_index = np.random.randint(0, num_city)
result.append(result[start_index].copy())
continue
current = start_index
rest.remove(current)
# 找到一条最近邻路径
result_one = [current]
while len(rest) != 0:
tmp_min = math.inf
tmp_choose = -1
for x in rest:
if dis_mat[current][x] < tmp_min:
tmp_min = dis_mat[current][x]
tmp_choose = x
current = tmp_choose
result_one.append(tmp_choose)
rest.remove(tmp_choose)
result.append(result_one)
start_index += 1
return result
# 计算不同城市之间的距离
def compute_dis_mat(self, num_city, location):
dis_mat = np.zeros((num_city, num_city))
for i in range(num_city):
for j in range(num_city):
if i == j:
dis_mat[i][j] = np.inf
continue
a = location[i]
b = location[j]
tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
dis_mat[i][j] = tmp
return dis_mat
# 计算路径长度
def compute_pathlen(self, path, dis_mat):
try:
a = path[0]
b = path[-1]
except:
import pdb
pdb.set_trace()
result = dis_mat[a][b]
for i in range(len(path) - 1):
a = path[i]
b = path[i + 1]
result += dis_mat[a][b]
return result
# 计算种群适应度
def compute_adp(self, fruits):
adp = []
for fruit in fruits:
if isinstance(fruit, int):
import pdb
pdb.set_trace()
length = self.compute_pathlen(fruit, self.dis_mat)
adp.append(1.0 / length)
return np.array(adp)
def swap_part(self, list1, list2):
index = len(list1)
list = list1 + list2
list = list[::-1]
return list[:index], list[index:]
def ga_cross(self, x, y):
len_ = len(x)
assert len(x) == len(y)
path_list = [t for t in range(len_)]
order = list(random.sample(path_list, 2))
order.sort()
start, end = order
# 找到冲突点并存下他们的下标,x中存储的是y中的下标,y中存储x与它冲突的下标
tmp = x[start:end]
x_conflict_index = []
for sub in tmp:
index = y.index(sub)
if not (index >= start and index < end):
x_conflict_index.append(index)
y_confict_index = []
tmp = y[start:end]
for sub in tmp:
index = x.index(sub)
if not (index >= start and index < end):
y_confict_index.append(index)
assert len(x_conflict_index) == len(y_confict_index)
# 交叉
tmp = x[start:end].copy()
x[start:end] = y[start:end]
y[start:end] = tmp
# 解决冲突
for index in range(len(x_conflict_index)):
i = x_conflict_index[index]
j = y_confict_index[index]
y[i], x[j] = x[j], y[i]
assert len(set(x)) == len_ and len(set(y)) == len_
return list(x), list(y)
def ga_parent(self, scores, ga_choose_ratio):
sort_index = np.argsort(-scores).copy()
sort_index = sort_index[0:int(ga_choose_ratio * len(sort_index))]
parents = []
parents_score = []
for index in sort_index:
parents.append(self.fruits[index])
parents_score.append(scores[index])
return parents, parents_score
def ga_choose(self, genes_score, genes_choose):
sum_score = sum(genes_score)
score_ratio = [sub * 1.0 / sum_score for sub in genes_score]
rand1 = np.random.rand()
rand2 = np.random.rand()
for i, sub in enumerate(score_ratio):
if rand1 >= 0:
rand1 -= sub
if rand1 < 0:
index1 = i
if rand2 >= 0:
rand2 -= sub
if rand2 < 0:
index2 = i
if rand1 < 0 and rand2 < 0:
break
return list(genes_choose[index1]), list(genes_choose[index2])
def ga_mutate(self, gene):
path_list = [t for t in range(len(gene))]
order = list(random.sample(path_list, 2))
start, end = min(order), max(order)
tmp = gene[start:end]
# np.random.shuffle(tmp)
tmp = tmp[::-1]
gene[start:end] = tmp
return list(gene)
def ga(self):
# 获得优质父代
scores = self.compute_adp(self.fruits)
# 选择部分优秀个体作为父代候选集合
parents, parents_score = self.ga_parent(scores, self.ga_choose_ratio)
tmp_best_one = parents[0]
tmp_best_score = parents_score[0]
# 新的种群fruits
fruits = parents.copy()
# 生成新的种群
while len(fruits) < self.num_total:
# 轮盘赌方式对父代进行选择
gene_x, gene_y = self.ga_choose(parents_score, parents)
# 交叉
gene_x_new, gene_y_new = self.ga_cross(gene_x, gene_y)
# 变异
if np.random.rand() < self.mutate_ratio:
gene_x_new = self.ga_mutate(gene_x_new)
if np.random.rand() < self.mutate_ratio:
gene_y_new = self.ga_mutate(gene_y_new)
x_adp = 1. / self.compute_pathlen(gene_x_new, self.dis_mat)
y_adp = 1. / self.compute_pathlen(gene_y_new, self.dis_mat)
# 将适应度高的放入种群中
if x_adp > y_adp and (not gene_x_new in fruits):
fruits.append(gene_x_new)
elif x_adp <= y_adp and (not gene_y_new in fruits):
fruits.append(gene_y_new)
self.fruits = fruits
return tmp_best_one, tmp_best_score
def run(self):
BEST_LIST = None
best_score = -math.inf
self.best_record = []
for i in range(1, self.iteration + 1):
tmp_best_one, tmp_best_score = self.ga()
self.iter_x.append(i)
self.iter_y.append(1. / tmp_best_score)
if tmp_best_score > best_score:
best_score = tmp_best_score
BEST_LIST = tmp_best_one
self.best_record.append(1./best_score)
print(i,1./best_score)
print(1./best_score)
return self.location[BEST_LIST], 1. / best_score
# 读取数据
def read_tsp(path):
lines = open(path, 'r').readlines()
assert 'NODE_COORD_SECTION\n' in lines
index = lines.index('NODE_COORD_SECTION\n')
data = lines[index + 1:-1]
tmp = []
for line in data:
line = line.strip().split(' ')
if line[0] == 'EOF':
continue
tmpline = []
for x in line:
if x == '':
continue
else:
tmpline.append(float(x))
if tmpline == []:
continue
tmp.append(tmpline)
data = tmp
return data
data = read_tsp('data/st70.tsp')
data = np.array(data)
data = data[:, 1:]
Best, Best_path = math.inf, None
model = GA(num_city=data.shape[0], num_total=25, iteration=500, data=data.copy())
path, path_len = model.run()
if path_len < Best:
Best = path_len
Best_path = path
# 加上一行因为会回到起点
fig, axs = plt.subplots(2, 1, sharex=False, sharey=False)
axs[0].scatter(Best_path[:, 0], Best_path[:,1])
Best_path = np.vstack([Best_path, Best_path[0]])
axs[0].plot(Best_path[:, 0], Best_path[:, 1])
axs[0].set_title('规划结果')
iterations = range(model.iteration)
best_record = model.best_record
axs[1].plot(iterations, best_record)
axs[1].set_title('收敛曲线')
plt.show()
这里需要导入数据集
st70.tsp
NAME: st70
TYPE: TSP
COMMENT: 70-city problem (Smith/Thompson)
DIMENSION: 70
EDGE_WEIGHT_TYPE : EUC_2D
NODE_COORD_SECTION
1 64 96
2 80 39
3 69 23
4 72 42
5 48 67
6 58 43
7 81 34
8 79 17
9 30 23
10 42 67
11 7 76
12 29 51
13 78 92
14 64 8
15 95 57
16 57 91
17 40 35
18 68 40
19 92 34
20 62 1
21 28 43
22 76 73
23 67 88
24 93 54
25 6 8
26 87 18
27 30 9
28 77 13
29 78 94
30 55 3
31 82 88
32 73 28
33 20 55
34 27 43
35 95 86
36 67 99
37 48 83
38 75 81
39 8 19
40 20 18
41 54 38
42 63 36
43 44 33
44 52 18
45 12 13
46 25 5
47 58 85
48 5 67
49 90 9
50 41 76
51 25 76
52 37 64
53 56 63
54 10 55
55 98 7
56 16 74
57 89 60
58 48 82
59 81 76
60 29 60
61 17 22
62 5 45
63 79 70
64 9 100
65 17 82
66 74 67
67 10 68
68 48 19
69 83 86
70 84 94
EOF
# -*- encoding: utf-8 -*-
import numpy as np
import pandas as pd
from Draw import *
class TSP(object):
citys = np.array([]) # 城市数组
citys_name = np.array([]) #城市名字数组
pop_size = 50 # 种群大小
c_rate = 0.7 # 交叉率
m_rate = 0.05 # 突变率
pop = np.array([]) # 种群数组
fitness = np.array([]) # 适应度数组(距离)
city_size = -1 # 标记城市数目
ga_num = 200 # 最大迭代次数
best_dist = -1 # 记录目前最优距离
best_gen = [] # 记录目前最优旅行方案
dw = Draw() # 绘图类
#初始化数据
def __init__(self, c_rate, m_rate, pop_size, ga_num):
self.fitness = np.zeros(self.pop_size)
self.c_rate = c_rate
self.m_rate = m_rate
self.pop_size = pop_size
self.ga_num = ga_num
def init(self):
tsp = self
tsp.load_Citys2() # 加载城市数据,调用City2
tsp.pop = tsp.creat_pop(tsp.pop_size) # 创建种群
tsp.fitness = tsp.get_fitness(tsp.pop) # 计算初始种群适应度
tsp.dw.bound_x = [np.min(tsp.citys[:, 0]), np.max(tsp.citys[:, 0])] # 计算绘图时的X界,min,max
tsp.dw.bound_y = [np.min(tsp.citys[:, 1]), np.max(tsp.citys[:, 1])] # 计算绘图时的Y界
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y) # 设置边界
def creat_pop(self, size):
pop = []
for i in range(size):
gene = np.arange(self.citys.shape[0]) # 问题的解,基因,种群中的个体:[0,...,city_size]
np.random.shuffle(gene) # 打乱数组[0,...,city_size]
pop.append(gene) # 加入种群
#array数组
return np.array(pop)
def get_fitness(self, pop):
d = np.array([]) # 适应度记录数组
for i in range(pop.shape[0]):#行
gen = pop[i] # 取其中一条基因(编码解,个体)
dis = self.gen_distance(gen) # 计算此基因优劣(距离长短)
dis = self.best_dist / dis # 当前最优距离除以当前pop[i](个体)距离;越近适应度越高,最优适应度为1
d = np.append(d, dis) # 保存适应度pop[i] d=d.append(dis)
return d
def get_local_fitness(self, gen, i):
'''
计算地i个城市的邻域
交换基因数组中任意两个值组成的解集:称为邻域。计算领域内所有可能的适应度
:param gen:城市路径
:param i:第i城市
:return:第i城市的局部适应度
'''
di = 0
fi = 0
if i == 0:
di = self.ct_distance(self.citys[gen[0]], self.citys[gen[-1]])
else:
di = self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]])
od = []
for j in range(self.city_size):
if i != j:
#交换基因数组中任意两个值组成的解集:称为邻域。计算领域内所有可能的适应度
od.append(self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]]))
mind = np.min(od)
fi = di - mind
return fi
def EO(self, gen):
# 极值优化,传统遗传算法性能不好,这里混合EO
# 其会在整个基因的领域内,寻找一个最佳变换以更新基因
local_fitness = []
for g in range(self.city_size):
f = self.get_local_fitness(gen, g)
local_fitness.append(f)
max_city_i = np.argmax(local_fitness)
maxgen = np.copy(gen)
if 1 < max_city_i < self.city_size - 1:
for j in range(max_city_i):
maxgen = np.copy(gen)
jj = max_city_i
while jj < self.city_size:
gen1 = self.exechange_gen(maxgen, j, jj)
d = self.gen_distance(maxgen)
d1 = self.gen_distance(gen1)
if d > d1:
maxgen = gen1[:]
jj += 1
gen = maxgen
return gen
def exechange_gen(self, gen, i, j):
# 函数:交换基因中i,j值
c = gen[j]
gen[j] = gen[i]
gen[i] = c
return gen
def select_pop(self, pop):
# 选择种群,优胜劣汰,策略1:低于平均的要替换改变
best_f_index = np.argmax(self.fitness)
#av表示平均数
av = np.median(self.fitness, axis=0)
for i in range(self.pop_size):
if i != best_f_index and self.fitness[i] < av:
pi = self.cross(pop[best_f_index], pop[i])
pi = self.mutate(pi)
pop[i, :] = pi[:]
return pop
def select_pop2(self, pop):
# 选择种群,优胜劣汰,策略2:轮盘赌,适应度低的替换的概率大
probility = self.fitness / self.fitness.sum()
idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=probility)
n_pop = pop[idx, :]
return n_pop
def cross(self, parent1, parent2):
"""交叉p1,p2的部分基因片段"""
#交叉率大于设定的,退出,返回parent1
if np.random.rand() > self.c_rate:
return parent1
#在index1与index2进行交叉基因片段
index1 = np.random.randint(0, self.city_size - 1)
index2 = np.random.randint(index1, self.city_size - 1)
tempGene = parent2[index1:index2] # 交叉的基因片段,例如:[20,24]
#newGene用来储存
newGene = []
p1len = 0
#对parent1的数据进行遍历
for g in parent1:
#若等于索引值,直接加上交叉的基因片段
if p1len == index1:
newGene.extend(tempGene) # 插入基因片段
#如果g不在交叉的基因片段,也加上,避免重复。
if g not in tempGene:
newGene.append(g)
p1len += 1
newGene = np.array(newGene)
#检查一下是不是城市的数量
if newGene.shape[0] != self.city_size:
print('c error')
return self.creat_pop(1)
# return parent1
return newGene
def mutate(self, gene):
"""突变"""
if np.random.rand() > self.m_rate:
return gene
#随机生成两个索引节点,
#np.random.randint返回一个随机整型数,范围从低(包括)到高(不包括),即[low, high)。
index1 = np.random.randint(0, self.city_size - 1)
index2 = np.random.randint(index1, self.city_size - 1)
newGene = self.reverse_gen(gene, index1, index2)
if newGene.shape[0] != self.city_size:
print('m error')
return self.creat_pop(1)
return newGene
def reverse_gen(self, gen, i, j):
# 函数:翻转基因中i到j之间的基因片段
#i>=j,j=33,生成的index1,index2发生错误。
if i >= j:
return gen
if j > self.city_size - 1:
return gen
#先做一个备份parent1
parent1 = np.copy(gen)
#tempGene为parent1的i-j
tempGene = parent1[i:j]
newGene = []
p1len = 0
#对parent1进行遍历,
for g in parent1:
if p1len == i:
newGene.extend(tempGene[::-1]) # 插入基因片段(步长为-1,倒着插入)
if g not in tempGene:
newGene.append(g) #如果g不在tempGene,追加上
p1len += 1
return np.array(newGene)
def evolution(self):
# 主程序:迭代进化种群
tsp = self
#ga_num 最大迭代次数
x_data = []
y_data = []
for i in range(self.ga_num):
#最好的索引,argmax返回的是最大数的索引
best_f_index = np.argmax(tsp.fitness)
worst_f_index = np.argmin(tsp.fitness)
#本地最好的路线,将种群(最好的索引),local_best_gen是个1*34
local_best_gen = tsp.pop[best_f_index]
#最优的距离
local_best_dist = tsp.gen_distance(local_best_gen)
if i == 0:
#第一个,初始化,以下两个存着最好的
tsp.best_gen = local_best_gen
tsp.best_dist = tsp.gen_distance(local_best_gen)
#出现更优秀的路程
if local_best_dist < tsp.best_dist:
tsp.best_dist = local_best_dist # 记录最优值(距离值)
tsp.best_gen = local_best_gen # 记录最个体基因(1*34)的基因,一个路线
# 绘图
tsp.dw.ax.cla()
tsp.re_draw()
#相当于sleep(0.001)
tsp.dw.plt.pause(0.001)
else:
tsp.pop[worst_f_index] = self.best_gen
#打印出基因代数和距离
print('gen:%d evo,best dist :%s' % (i, self.best_dist))
x_data.append(i)
y_data.append(self.best_dist)
# 设置数据图的标题
tsp.pop = tsp.select_pop(tsp.pop) # 选择淘汰种群
tsp.fitness = tsp.get_fitness(tsp.pop) # 计算种群适应度
for j in range(self.pop_size):
r = np.random.randint(0, self.pop_size - 1)
if j != r:
tsp.pop[j] = tsp.cross(tsp.pop[j], tsp.pop[r]) # 交叉种群中第j,r个体的基因
tsp.pop[j] = tsp.mutate(tsp.pop[j]) # 突变种群中第j个体的基因
tsp.best_dist = tsp.gen_distance(self.best_gen) # 记录最优值
plt.title('TSP问题:34城市旅游')
# 第一个列表代表横坐标的值,第二个代表纵坐标的值
plt.plot(x_data, y_data)
# 设置两条坐标轴的标签
plt.xlabel("经度")
plt.ylabel("纬度")
# print(x_data)
# print(y_data)
def load_Citys2(self, file='china.csv', delm=';'):
# 中国34城市经纬度
#分delimiter隔符。header头,从哪里开始读
data = pd.read_csv(file, delimiter=delm, header=None).values
#所有行,第1-2列
self.citys = data[:, 1:]
#第0列,所有行
self.citys_name = data[:, 0]
#城市数量shape[0]为行数;shape[0]为列数
self.city_size = data.shape[0]
def gen_distance(self, gen):
# 计算基因所代表的总旅行距离
#传入的数据为种群数
distance = 0.0
for i in range(-1, len(self.citys) - 1):
index1, index2 = gen[i], gen[i + 1]
city1, city2 = self.citys[index1], self.citys[index2]
#距离公式
distance += np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
return distance
def ct_distance(self, city1, city2):
# 计算2城市之间的距离
d = np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
return d
def draw_citys_way(self, gen):
'''
根据一条基因gen绘制一条旅行路线
:param gen:
:return:
'''
tsp = self
dw = self.dw
m = gen.shape[0]#多少行
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
for i in range(m):
if i < m - 1:
#获得基因地点的代数值
best_i = tsp.best_gen[i]
next_best_i = tsp.best_gen[i + 1]
#城市
best_icity = tsp.citys[best_i]
next_best_icity = tsp.citys[next_best_i]
dw.draw_line(best_icity, next_best_icity)
#首位相连
start = tsp.citys[tsp.best_gen[0]]
end = tsp.citys[tsp.best_gen[-1]]
dw.draw_line(end, start)
def draw_citys_name(self, gen, size=5):
'''
根据一条基因gen(路线)绘制对应城市名称
'''
tsp = self
m = gen.shape[0]
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
for i in range(m):
c = gen[i]
best_icity = tsp.citys[c]
tsp.dw.draw_text(best_icity[0], best_icity[1], tsp.citys_name[c], 10)
def re_draw(self):
# 重绘图;每次迭代后绘制一次,动态展示。
tsp = self
tsp.dw.draw_points(tsp.citys[:, 0], tsp.citys[:, 1])
tsp.draw_citys_name(tsp.pop[0], 8)
tsp.draw_citys_way(self.best_gen)
def main():
#
tsp = TSP(0.5, 0.1, 100, 500)
tsp.init()
tsp.evolution()
tsp.re_draw()
tsp.dw.plt.show()
if __name__ == '__main__':
main()
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import matplotlib.animation as animation
class Draw(object):
#边界值
bound_x = []
bound_y = []
def __init__(self):
self.fig, self.ax = plt.subplots()
self.plt = plt
self.set_font()
def draw_line(self, p_from, p_to):
#画线函数
#储存两个点的坐标
line1 = [(p_from[0], p_from[1]), (p_to[0], p_to[1])]
#zip匹配
(line1_xs, line1_ys) = zip(*line1)
self.ax.add_line(Line2D(line1_xs, line1_ys, linewidth=1, color='blue'))
def draw_points(self, pointx, pointy):
#画点
self.ax.plot(pointx, pointy, 'ro')
#设置边界
def set_xybound(self, x_bd, y_bd):
self.ax.axis([x_bd[0], x_bd[1], y_bd[0], y_bd[1]])
def draw_text(self, x, y, text, size=8):
#写入文本
self.ax.text(x, y, text, fontsize=size)
def set_font(self, ft_style='SimHei'):
plt.rcParams['font.sans-serif'] = [ft_style] #用来正常显示中文标签
import matplotlib.pyplot as plt # 调用matplotlib中的子模块pyplot绘制折线图
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 定义2个列表分别作为X轴、Y轴数据
x_data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306,
307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350,
351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416,
417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438,
439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460,
461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499]
y_data = [564.3572005522793, 525.8139896243653, 428.1402039165018, 395.73743500834706, 394.06860429583867,
373.684464645136, 365.60282673151573, 345.53960499838325, 331.2057904610075, 318.760364597339,
303.162734978924, 301.42654142792907, 324.64583395454457, 301.42654142792907, 286.65204026600344,
286.65204026600344, 282.273279917727, 282.273279917727, 280.1240489659227, 280.1240489659227,
263.21414723204833, 254.22777921677803, 254.22777921677803, 250.71667881027474, 250.71667881027474,
250.50756156870992, 246.24627654938107, 243.8041742198946, 240.15416946358778, 233.2661303383399,
233.2661303383399, 239.59565159058116, 245.4156684272969, 228.28636969404505, 223.25718187742706,
234.39093411202532, 228.28636969404505, 228.28636969404505, 228.28636969404505, 228.28636969404505,
223.25718187742706, 223.25718187742706, 223.25718187742706, 223.25718187742706, 223.25718187742706,
223.25718187742706, 237.62255381361274, 218.7219498855295, 218.7219498855295, 218.7219498855295,
218.7219498855295, 213.88717907524358, 213.88717907524358, 213.88717907524358, 213.88717907524358,
213.88717907524358, 213.88717907524358, 210.38478374497757, 209.33239248439264, 209.33239248439264,
206.78401520265885, 204.6494179326049, 202.52449291907507, 202.52449291907507, 209.40591607095607,
202.52449291907507, 202.52449291907507, 196.47995538838418, 196.47995538838418, 190.37500614252744,
190.37500614252744, 189.59159577864688, 189.59159577864688, 208.0505225509335, 188.16445411312182,
188.16445411312182, 183.3306118846393, 183.3306118846393, 183.3306118846393, 180.91006531329387,
180.91006531329387, 180.91006531329387, 180.91006531329387, 180.1372614132791, 180.1372614132791,
173.88941629266455, 173.88941629266455, 176.59810679235267, 170.69606582130436, 170.69606582130436,
170.69606582130436, 170.69606582130436, 170.69606582130436, 168.07668182016852, 168.07668182016852,
168.07668182016852, 168.07668182016852, 168.07668182016852, 168.07668182016852, 168.07668182016852,
168.07668182016852, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 177.3790464315465,
167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
167.8576491945162, 167.8576491945162, 167.8576491945162, 167.61076548111026, 167.61076548111026,
164.97138190423385, 164.97138190423385, 164.97138190423385, 164.97138190423385, 164.97138190423385,
164.72449819082792, 164.54586334812686, 164.54586334812686, 199.208730578168, 164.54586334812686,
164.54586334812686, 164.54586334812686, 164.54586334812686, 164.29897963472092, 164.29897963472092,
164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
164.29897963472092, 164.29897963472092, 185.88553720859375, 164.29897963472092, 164.29897963472092,
164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
164.29897963472092, 164.29897963472092, 164.29897963472092, 162.57964890814006, 164.29897963472092,
162.57964890814006, 158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737,
158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737,
158.7673551900737, 158.7673551900737, 158.7673551900737, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 165.4458885670924, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 191.02831038858773, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 171.65859112307524, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 164.0340772847696, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 179.9211681457678, 179.9211681457678,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
163.66825012378013, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 171.91025362935008, 158.1419649942265, 158.1419649942265,
209.80381193148267, 191.60574674226325, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 175.8142105909829, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
167.026358254871, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 176.6464998788, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 167.23953199487363, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 192.04319689552514,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 163.16329458342935, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 200.09613901232325, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 161.73403495002682, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 170.9199683340315,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
194.74385775914007, 176.00797889997622, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 161.17029153503222, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
158.1419649942265, 158.1419649942265, 158.1419649942265, 200.08345964477837]
# 设置数据图的标题
plt.title('迭代代数与距离的关系')
# 第一个列表代表横坐标的值,第二个代表纵坐标的值
plt.plot(x_data, y_data)
# 设置两条坐标轴的标签
plt.xlabel("迭代代数")
plt.ylabel("距离/KM")
# 调用show()函数显示图形
plt.show()
北京 ;116.46;39.92
天津 ;117.2;39.13
上海 ;121.48;31.22
重庆 ;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
杭州;120.19;30.26
福州;119.3;26.08
南昌;115.89;28.68
长沙;113;28.21
武汉;114.31;30.52
广州;113.23;23.16
台北;121.5;25.05
海口;110.35;20.02
兰州;103.73;36.03
西安;108.95;34.27
成都;104.06;30.67
贵阳;106.71;26.57
昆明;102.73;25.04
香港;114.1;22.2
澳门;113.33;22.13
视频展示
b站视频链接