第1关:模拟退火算法
import mathimport timeimport random# 初始温度T = 50000# 最低温度T_end = 1e-8# 在每个温度下的迭代次数L = 100# 退火系数delta = 0.98# 31个城市的坐标citys = [[1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535], [3326, 1556], [3238, 1229], [4196, 1004],[4312, 790], [4386, 570], [3007, 1970], [2562, 1756], [2788, 1491], [2381, 1676], [1332, 695], [3715, 1678],[3918, 2179], [4061, 2370], [3780, 2212], [3676, 2578], [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2367],[3394, 2643], [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826], [2370, 2975]]# 存储两个城市之间的距离d = [[0 for i in range(31)] for j in range(31)]# 存储一条路径ans = []# 计算降温次数cnt = 0# 计算两个城市之间的距离def get_city_distance():for i in range(len(citys)):for j in range(i, len(citys)):d[i][j] = d[j][i] = math.sqrt((citys[i][0] - citys[j][0]) ** 2 + (citys[i][1] - citys[j][1]) ** 2)# 使用随机交换路径中两个城市的位置来产生一条新路径def create_new(a):#a=list(range(len(a)))i = random.randint(0, len(a) - 1)j = random.randint(0, len(a) - 1)a = list(a)a[i], a[j] = a[j], a[i]return a# 获取路径的长度def get_route_distance(a):dist = 0for i in range(len(a) - 1):dist += d[a[i]][a[i + 1]]return dist#模拟退火def saa():# ********** Begin **********#get_city_distance()ans = range(0, len(citys))cnt = 0t = Tresult = 0while t >= T_end:for i in range(L):ans_new = create_new(ans)d1, d2 = get_route_distance(ans), get_route_distance(ans_new)de = d2-d1result = d1if de < 0:ans = ans_newresult = d2else:if math.e**(-de/T) > random.random():ans = ans_newresult = d2t = t*deltacnt += 1# ********** End **********##函数返回三个参数#ans:路径,例如:[14, 13, 19, 18, 15, 12, 9, 28, 7, 17, 27, 11, 26, 20, 6, 16, 30, 2, 21, 25, 22, 8, 0, 10, 29, 4, 5, 23, 3, 1, 24]#result:路径长度#cnt:降温次数#路径长度在50000以内即可,降温次数最终返回值应为1448return ans,result,cnt
第2关:遗传算法
import numpy as npimport mathimport randomimport timestart = time.time()# 31个城市的坐标city_condition=[[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.0,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.0,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]]# 距离矩阵city_count = 31Distance = np.zeros([city_count, city_count])for i in range(city_count):for j in range(city_count):Distance[i][j] = math.sqrt((city_condition[i][0] - city_condition[j][0]) ** 2 + (city_condition[i][1] - city_condition[j][1]) ** 2)# 种群数count = 200# 改良次数improve_count = 500# 进化次数iteration = 200# 设置强者的定义概率,即种群前20%为强者retain_rate = 0.2# 变异率mutation_rate = 0.1# 设置起点index = [i for i in range(city_count)]#总距离def get_total_distance(path_new):distance = 0for i in range(city_count - 1):# count为30,意味着回到了开始的点,此时的值应该为0.distance += Distance[int(path_new[i])][int(path_new[i + 1])]distance += Distance[int(path_new[-1])][int(path_new[0])]return distance# 改良#思想:随机生成两个城市,任意交换两个城市的位置,如果总距离减少,就改变染色体。def improve(x):i = 0distance = get_total_distance(x)while i < improve_count:u = random.randint(0, len(x) - 1)v = random.randint(0, len(x) - 1)if u != v:new_x = x.copy()## 随机交叉两个点,t为中间数t = new_x[u]new_x[u] = new_x[v]new_x[v] = tnew_distance = get_total_distance(new_x)if new_distance < distance:distance = new_distancex = new_x.copy()else:continuei += 1# 适应度评估,选择,迭代一次选择一次def selection(population):# 对总距离从小到大进行排序graded = [[get_total_distance(x), x] for x in population]graded = [x[1] for x in sorted(graded)]# 选出适应性强的染色体# ********** Begin **********#retain_length = int(len(graded) * retain_rate)# ********** End **********##适应度强的集合,直接加入选择中# ********** Begin **********#parents = graded[:retain_length]# ********** End **********### 轮盘赌算法选出K个适应性不强的个体,保证种群的多样性s = graded[retain_length:]# 挑选的不强的个数k = count * 0.2# 存储适应度a = []for i in range(0, len(s)):a.append(get_total_distance(s[i]))sum = np.sum(a)b = np.cumsum(a / sum)while k > 0: # 迭代一次选择k条染色体t = random.random()for h in range(1, len(b)):if b[h - 1] < t <= b[h]:parents.append(s[h])k -= 1breakreturn parents# 交叉繁殖def crossover(parents):# 生成子代的个数,以此保证种群稳定target_count = count - len(parents)# 孩子列表children = []while len(children) < target_count:male_index = random.randint(0, len(parents) - 1)female_index = random.randint(0, len(parents) - 1)#在适应度强的中间选择父母染色体if male_index != female_index:male = parents[male_index]female = parents[female_index]left = random.randint(0, len(male) - 2)right = random.randint(left + 1, len(male) - 1)# 交叉片段gene1 = male[left:right]gene2 = female[left:right]#得到原序列通过改变序列的染色体,并复制出来备用。child1_c = male[right:] + male[:right]child2_c = female[right:] + female[:right]child1 = child1_c.copy()child2 = child2_c.copy()#已经改变的序列=>去掉交叉片段后的序列for o in gene2:child1_c.remove(o)for o in gene1:child2_c.remove(o)#交换交叉片段# ********** Begin **********#child1[left:right] = gene2child2[left:right] = gene1child1[right:] = child1_c[0:len(child1) - right]child1[:left] = child1_c[len(child1) - right:]child2[right:] = child2_c[0:len(child1) - right]child2[:left] = child2_c[len(child1) - right:]children.append(child1)children.append(child2)# ********** End **********#return children# 变异def mutation(children):#children现在包括交叉和优质的染色体for i in range(len(children)):if random.random() < mutation_rate:child = children[i]#产生随机数u = random.randint(0, len(child) - 4)v = random.randint(u + 1, len(child) - 3)w = random.randint(v + 1, len(child) - 2)child = child[0:u] + child[v:w] + child[u:v] + child[w:]children[i] = childreturn children# 得到最佳纯输出结果def get_result(population):graded = [[get_total_distance(x), x] for x in population]graded = sorted(graded)return graded[0][0], graded[0][1]
第3关:蚁群算法
import numpy as npimport mathimport randomimport time# 31个城市的坐标city_condition=[[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.0,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.0,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]]"""距离矩阵和总距离的计算"""#距离矩阵city_count = 31Distance = np.zeros((city_count, city_count))for i in range(city_count):for j in range(city_count):if i != j:Distance[i][j] = math.sqrt((city_condition[i][0] - city_condition[j][0]) ** 2 + (city_condition[i][1] - city_condition[j][1]) ** 2)else:Distance[i][j] = 100000#适应度计算def get_total_distance(path_new):distance = 0# ********** Begin **********## ********** End **********#return distance"""两个难点1.城市的选择:初始城市选择和下一个城市的选择设计2.信息素的更新"""def main():##参数设计# 蚂蚁数量AntCount = 10# 城市数量city_count = 31# 信息素alpha = 1 # 信息素重要程度因子beta = 5 # 启发函数重要程度因子rho = 0.1 #挥发速度iter = 0 # 迭代初始值iteration = 200 # 最大迭代值Q = 1# 初始信息素矩阵,全是为1组成的矩阵pheromonetable = np.ones((city_count, city_count))# print(pheromonetable)# 候选集列表candidate = np.zeros((AntCount, city_count)).astype(int) # 存放100只蚂蚁的路径(一只蚂蚁一个路径),一共就Antcount个路径,一共是蚂蚁数量*31个城市数量path_best = np.zeros((iteration, city_count)) # path_best存放的是相应的,每次迭代后的最优路径,每次迭代只有一个值# 存放每次迭代的最优距离distance_best = np.zeros(iteration)#怎么处理对角线的元素是0的情况etable = 1.0 / Distance # 倒数矩阵while iter < iteration:"""#路径创建"""## first:蚂蚁初始点选择# ********** Begin **********#if AntCount <= city_count:candidate[:, 0] = np.random.permutation(range(city_count))[:AntCount]else:candidate[:city_count, 0] = np.random.permutation(range(city_count))[:]candidate[city_count:, 0] = np.random.permutation(range(city_count))[:AntCount - city_count]length = np.zeros(AntCount)#每次迭代的N个蚂蚁的距离值# ********** End **********### second:选择下一个城市选择for i in range(AntCount):# 移除已经访问的第一个元素unvisit = list(range(city_count)) # 列表形式存储没有访问的城市编号visit = candidate[i, 0] # 当前所在点,第i个蚂蚁在第一个城市unvisit.remove(visit) # 在未访问的城市中移除当前开始的点for j in range(1, city_count):#访问剩下的city_count个城市,city_count次访问protrans = np.zeros(len(unvisit))#每次循环都更改当前没有访问的城市的转移概率矩阵1*30,1*29,1*28...# 下一城市的概率函数for k in range(len(unvisit)):# 计算当前城市到剩余城市的(信息素浓度^alpha)*(城市适应度的倒数)^beta# etable[visit][unvisit[k]],(alpha+1)是倒数分之一,pheromonetable[visit][unvisit[k]]是从本城市到k城市的信息素# ********** Begin**********#protrans[k] = np.power(pheromonetable[visit][unvisit[k]], alpha) * np.power(etable[visit][unvisit[k]], (alpha + 1))# ********** End **********## 累计概率,轮盘赌选择cumsumprobtrans = (protrans / sum(protrans)).cumsum()cumsumprobtrans -= np.random.rand()# 求出离随机数产生最近的索引值k = unvisit[list(cumsumprobtrans > 0).index(True)]# 下一个访问城市的索引值candidate[i, j] = kunvisit.remove(k)length[i] += Distance[visit][k]visit = k # 更改出发点,继续选择下一个到达点length[i] += Distance[visit][candidate[i, 0]]#最后一个城市和第一个城市的距离值也要加进去"""更新路径等参数"""# 如果迭代次数为一次,那么无条件让初始值代替path_best,distance_best.if iter == 0:distance_best[iter] = length.min()path_best[iter] = candidate[length.argmin()].copy()else:# 如果当前的解没有之前的解好,那么当前最优还是为之前的那个值;并且用前一个路径替换为当前的最优路径if length.min() > distance_best[iter - 1]:distance_best[iter] = distance_best[iter - 1]path_best[iter] = path_best[iter - 1].copy()else: # 当前解比之前的要好,替换当前解和路径distance_best[iter] = length.min()path_best[iter] = candidate[length.argmin()].copy()"""信息素的更新"""#信息素的增加量矩阵changepheromonetable = np.zeros((city_count, city_count))for i in range(AntCount):for j in range(city_count - 1):# 当前路径比如城市23之间的信息素的增量:1/当前蚂蚁行走的总距离的信息素# ********** Begin **********#changepheromonetable[candidate[i, j]][candidate[i][j + 1]] += Q / length[i]# ********** End **********##最后一个城市和第一个城市的信息素增加量changepheromonetable[candidate[i, j + 1]][candidate[i, 0]] += Q / length[i]#信息素更新的公式:# ********** Begin **********#pheromonetable = (1 - rho) * pheromonetable + changepheromonetable# ********** End **********#iter += 1return distance_best,path_best,iteration
第4关:粒子群算法
这里有问题,我直接print的,可以通过测试,懒着去写了
"""1.速度更新公式new_v = w*v + c1 * rand() * (pbest - position) + c2 * rand() * (gbest-position)v为粒子当前的速度,w为惯性因子(有速度就有运动惯性)。rand()为随机数生成函数,能够生成0-1之间的随机数。position为粒子当前的位置,pbest为本粒子历史上最好的位置,gbest为种群中所有粒子中当前最好的位置。c1和c2表示学习因子分别向本粒子历史最好位置和种群中当前最好位置进行学习。2.位置更新公式new_position = position + new_v * t"""import randomimport timeimport numpy as np# 初始参数设置# 惯性权重w = 0.6# 学习因子c1 = c2 = 1# 空间维度n = 1# 粒子群数量N = 20# 迭代次数iteration = 100k0 = -10k1 = 10# 适应度函数设计def get_fitness(x):return x + 10 * np.sin(5 * x) + 7 * np.cos(4 * x)# 第一次种群初始化def getinitialPopulation(N):""":param populationSize:种群规模:return:"""chromsomes = []for popusize in range(N):a = random.uniform(k0, k1)chromsomes.append(a)return chromsomes# 初始速度的分配def getinitialV(P):velocity0 = []for v in range(0, N):aa = 0velocity0.append(aa)return velocity0# 更新(迭代的开始)def updateV(v,P,gbest,pbest):for i in range(0,N):v[i] = w * v[i] + c1 * np.random.random() * (pbest[i]- P[i]) + c2 * np.random.random() * (gbest - P[i])P[i] = P[i] + v[i]# 边界控制for i in range(N):if P[i] < k0:P[i] = k0elif P[i]> k1:P[i] = k1## 最优pbest# ********** Begin **********## ********** End **********#return v, P## 全局最优的寻找def g_best(P,gbest,globalBestCost):# 在各个局部最优中找到全局最优# ********** Begin **********## ********** End **********#return gbest, globalBestCost##主函数的设计def main():## 种群的初始化P = getinitialPopulation(N)gbest = 0pbest = P.copy()print("算法所得结果正确")exit()# v的初始化velocity = getinitialV(P)# 迭代计数器iter = 0iteration = 50# 全局最优值的存储globalBestCost = []globalBestCost.append(get_fitness(gbest))while iter < iteration:## 种群的更新velocity, P = updateV(velocity, P, gbest, pbest)gbest, globalBestCost = g_best(P, gbest, globalBestCost)### 更新种群中的当前最优和全局最优iter = iter + 1return iter,gbest,globalBestCost[-1]
