遺傳演算法求解TSP問題(python版)
簡介
改進和實現遺傳演算法,用以對旅行商問題(TSP問題)進行建模和近似求解,從而深入對啟發式演算法的理解。
演算法流程
遺傳演算法解決TSP的流程是以下幾部分:初始化種群、計算適應度函式、選擇、交叉、變異然後不斷重複直到找到理想的解。
模型設定
I 種群初始化。
需要設定的引數是隨機生成的初始解的數量,該數量過少會導致種群多樣性不足,數量過多會降低演算法的效率,我們設定種群規模(初始解數量為150)。
II 適應度函式。
根據資料集說明,其最優解採用的邊權重型別為:EDGE_WEIGHT_TYPE : EUC_2D,即兩城市之間的距離通過歐式距離計算。
我們得到對路徑的所有距離進行求和得到distance,令f=1/distance,即為適應度函式。
III 選擇
選擇,即在上一代生存的個體中,通過優勝劣汰,使適應性更強的解得以保留。具體而言首先將上一代種群中適應性最強的10%物種保留,然後通過輪盤轉賭法,以選擇概率為權重,挑出剩下的90%物種。
其中對於每個物種s_i)選擇概率計算公式為:
採用上述設定的原因是儘量讓適應度更強的物種活下來,同時防止適應性最強的物種因隨機性而被輪盤轉賭法淘汰。
IV 交叉
通過選擇倖存下的物種進行交叉的概率為70%,交叉的方式為單點交叉,即隨機選取一個節點,將交叉雙方該節點後的部分進行交換。在交換後,單個物種可能會出現有重複城市的情況,因此我們進行了去重操作,即記錄下重複的位置,使交叉雙方重複的節點進行交換。
V 變異
變異是遺傳演算法跳出區域性最優解的重要操作。在TSP問題中,變異操作是隨機選取物種的兩個節點,將節點中的城市順序顛倒。過往的研究表明,變異的概率大於0.5之後,遺傳演算法將退化為隨機搜尋。但考慮到跳出區域性最優解的重要性,因此我們設定變異的概率為20%。
實驗結果
算例一:
(1) 算例名稱:DJ38,城市:38,最短距離:6656
來源:http://www.math.uwaterloo.ca/tsp/world/countries.html#DJ
(2) 最優解:
29->28->20->13->9->0->1->3->2->4->5->6->7->8->11->10->18->17->16->15->12->14->19->22->25->24->21->23->27->26->30->35->33->32->37->36->34->31->29
(3) 視覺化結果
上部分圖片為官方給的路線圖,下部分圖片為我們求得的最優解。
(4) 演算法求得的最短距離 隨 求解時間 變化結果
(5) 解的質量
算例二
(1) 算例名稱:TSPLIB , qa194,城市:194,最短距離:9352
來源:http://www.math.uwaterloo.ca/tsp/world/countries.html#DJ
(2) 最優解路線:
143->149->153->156->163->162->160->155->144->148->145->138->137->141->139->136->133->131->129->126->124->125->113->110->103->100->98->93->97->89->88->81->61->58->35->62->84->85->64->19->0->5->7->15->12->22->24->16->13->10->6->3->1->2->4->8->9->11->14->18->29->31->30->34->37->40->45->43->41->49->48->54->53->51->52->55->47->42->39->33->38->26->36->50->46->57->60->66->72->65->67->63->69->76->83->80->78->82->87->92->95->94->91->96->99->109->111->107->106->104->105->102->90->73->68->59->56->44->28->21->27->32->17->20->23->25->71->77->74->75->70->79->86->101->108->112->118->121->117->130->128->120->116->115->114->119->122->123->127->132->134->142->147->159->165->170->184->192->180->183->187->188->190->191->189->193->181->175->168->171->178->185->186->182->173->172->174->176->177->179->169->161->166->167->164->158->157->154->135->150->146->151->152->140->143
(3) 視覺化結果
上部分圖片為官方給的路線圖,下部分圖片為我們求得的最優解。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201110231636375.png#pic_center
(4)演算法求得的最短距離 隨 求解時間 變化結果
(5)解的質量
總結
在城市數量較少時,該演算法的精度較高,且收斂速度較快。當城市數量多時,演算法容易收斂到區域性最小值。
實驗程式碼
# -*- coding: utf-8 -*-
"""
Created on Wed Jun 5 18:06:59 2019
@author: 1
"""
#匯入需要用到的包
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#from numba import jit
#初始化引數
species = 200
iters = 5000
def getListMaxNumIndex(num_list,topk=int(0.2*species)):
'''
獲取列表中最大的前n個數值的位置索引
'''
num_dict = {}
for i in range(len(num_list)):
num_dict[i] = num_list[i]
res_list = sorted(num_dict.items(),key=lambda e:e[1])
max_num_index = [one[0] for one in res_list[::-1][:topk]]
return max_num_index
#適應度函式
def calfit(trip, num_city):
total_dis = 0
for i in range(num_city):
cur_city = trip[i]
next_city = trip[i+1] % num_city
temp_dis = distance[cur_city][next_city]
total_dis = total_dis + temp_dis
return 1 / total_dis
def dis(trip, num_city):
total_dis = 0
for i in range(num_city):
cur_city = trip[i]
next_city = trip[i+1] % num_city
temp_dis = distance[cur_city][next_city]
total_dis = total_dis + temp_dis
return total_dis
#交叉函式
def crossover(father,mother):
num_city = len(father)
#indexrandom = [i for i in range(int(0.4*cronum),int(0.6*cronum))]
index_random = [i for i in range(num_city)]
pos = random.choice(index_random)
son1 = father[0:pos]
son2 = mother[0:pos]
son1.extend(mother[pos:num_city])
son2.extend(father[pos:num_city])
index_duplicate1 = []
index_duplicate2 = []
for i in range(pos, num_city):
for j in range(pos):
if son1[i] == son1[j]:
index_duplicate1.append(j)
if son2[i] == son2[j]:
index_duplicate2.append(j)
num_index = len(index_duplicate1)
for i in range(num_index):
son1[index_duplicate1[i]], son2[index_duplicate2[i]] = son2[index_duplicate2[i]], son1[index_duplicate1[i]]
return son1,son2
#變異函式
def mutate(sample):
num_city = len(sample)
part = np.random.choice(num_city,2,replace=False)
if part[0] > part[1]:
max_ = part[0]
min_ = part[1]
else:
max_ = part[1]
min_ = part[0]
after_mutate = sample[0:min_]
temp_mutate = list(reversed(sample[min_:max_]))
after_mutate.extend(temp_mutate)
after_mutate.extend(sample[max_:num_city])
return after_mutate
#讀取城市位置資料
import datetime
starttime = datetime.datetime.now()
#long running
df1 = pd.read_csv('size38.txt', sep=' ', header=None)
#df1 = pd.read_csv('size29.txt', sep=' ', header=None)
#df1 = pd.read_csv('size194.txt', sep=' ', header=None)
#df1 = pd.read_csv('size131.txt', sep=' ', header=None)
#df2 = pd.read_csv('st70.txt', sep=' ', header=None)
df1[0] = df1[0] - 1
plot = plt.plot(df1[1], df1[2], '*')
#計算各城市鄰接矩陣。
n = len(df1)
distance = np.zeros((n, n))
for i in range(n):
for j in range(n):
temp1 = np.power((df1.iloc[i,1] - df1.iloc[j,1]),2)
temp2 = np.power((df1.iloc[i,2] - df1.iloc[j,2]),2)
distance[i][j] = np.sqrt(temp1 + temp2)
#初始化種群,生成可能的解的集合
x = []
counter = 0
#for i in range(species):
while counter < species:
dna = np.random.permutation(range(n)).tolist()
start = dna[0]
dna.append(start)
if dna not in x:
x.append(dna)
counter = counter + 1
ctlist = []
dislist = []
ct = 0
while ct < iters:
ct = ct + 1
f = []
for i in range(species):
f.append(calfit(x[i], n))
#計算選擇概率
sig = sum(f)
p = (f / sig).tolist()
test = getListMaxNumIndex(p)
testnum = len(test)
newx = []
for i in range(testnum):
newx.append(x[test[i]])
#newx.append(x[test[i]])
index = [i for i in range(species)]
news = random.choices(index,weights=p,k=int(0.8*species))
newsnum = len(news)
for i in range(newsnum):
newx.append(x[news[i]])
m = int(species/2)
for i in range(0,m):
j = i + m - 1
#j=i+1
numx = len(newx[0])
if random.choice([1,2,3,4,5,6,7,8,9,10]) < 8:
tplist1 = newx[i][0:numx-1]
tplist2 = newx[j][0:numx-1]
crosslist1,crosslist2 = crossover(tplist1,tplist2)
if random.choice([1,2,3,4,5,6,7,8,9,10]) < 4:
crosslist1 = mutate(crosslist1)
crosslist2 = mutate(crosslist2)
end1 = crosslist1[0]
end2 = crosslist2[0]
crosslist1.append(end1)
crosslist2.append(end2)
newx[i] = crosslist1
newx[j] = crosslist2
x = newx
res = []
for i in range(species):
res.append(calfit(x[i], n))
result = 1 / max(res)
res1 = []
for i in range(species):
res1.append(dis(x[i], n))
result1 = min(res1)
print(ct)
print(result)
print(result1)
ctlist.append(ct)
dislist.append(result)
endtime = datetime.datetime.now()
print (endtime - starttime)
plk1 = []
plk2 = []
for i in range(len(x[0])):
plk2.append(df1.iloc[x[0][i], 2])
plk1.append(df1.iloc[x[0][i], 1])
plot = plt.plot(plk1, plk2, c='r')
plt.xlabel('x')
plt.ylabel('y')
plt.show()
plot = plt.plot(ctlist, dislist)
plt.xlabel('iters')
plt.ylabel('distance')
plt.show()
需要測試資料請聯絡博主,或者去我文中提供的來源自行下載。
相關文章
- 遺傳演算法解決TSP問題演算法
- 遺傳演算法解決旅行商問題(TSP)演算法
- 利用遺傳學演算法求解工作分配問題演算法
- 基於免疫演算法的TSP問題求解matlab模擬演算法Matlab
- 蟻群演算法java實現以及TSP問題蟻群演算法求解演算法Java
- python遺傳演算法(詳解)Python演算法
- 如何學習python遺傳演算法?Python演算法
- 旅行商問題(TSP)概述
- 遺傳演算法解決函式最佳化問題演算法函式
- python+gurobi求解排班問題Python
- 蟻群演算法介紹(以TSP問題為例)演算法
- Python遺傳演算法工具箱的使用(一)求解帶約束的單目標優化Python演算法優化
- 遺傳演算法演算法
- 粒子群演算法求解物流配送路線問題(python)演算法Python
- 分治演算法-求解棋盤覆蓋問題演算法
- Python遺傳演算法框架使用例項(二)多目標優化問題Geatpy for Python與Matlab的對比學習Python演算法框架優化Matlab
- Python-遺傳演算法君主交叉程式碼實現Python演算法
- 分治法求解問題
- Python求解錯,不知道哪裡有問題。。。Python
- 遺傳演算法(一):Basic GA演算法
- 遺傳演算法的基本框架演算法框架
- 多目標遺傳演算法NSGA-Ⅱ與其Python實現多目標投資組合優化問題演算法Python優化
- [經典演算法]海盜分金問題sql求解(貪心演算法)演算法SQL
- 基於Python的遺傳演算法特徵約簡(附程式碼)Python演算法特徵
- 人工智慧 (13) 遺傳演算法人工智慧演算法
- 10分鐘搞懂遺傳演算法演算法
- python中傳值和傳地址問題Python
- 智慧優化演算法——python實現免疫遺傳演算法的影像擬合優化演算法Python
- 樹遞迴問題的求解遞迴
- NP難問題求解綜述
- 遺傳演算法詳解與實驗演算法
- 遺傳演算法組卷使用心得演算法
- DPLL 演算法(求解k-SAT問題)詳解(C++實現)演算法C++
- 問一個 python 演算法題Python演算法
- 傳教士與食人者問題pythonPython
- 粒子群演算法和遺傳演算法的比較演算法
- 機器學習演算法(6)用Python實現用核支援向量機求解非線性問題機器學習演算法Python
- Unity中利用遺傳演算法訓練MLPUnity演算法