日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

遗传算法求最短路径(旅行商问题)python实现

發(fā)布時(shí)間:2024/9/30 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 遗传算法求最短路径(旅行商问题)python实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

問題描述
一個(gè)商品推銷員要去若干個(gè)城市推銷商品,該推銷員從一個(gè)城市出發(fā),需要經(jīng)過所有城市后,回到出發(fā)地。應(yīng)如何選擇行進(jìn)路線,以使總的行程最短。
對(duì)于n個(gè)城市的TSP,本文利用python分別實(shí)現(xiàn)遺傳算法對(duì)該問題的求解。

遺傳算法

原理見鏈接
遺傳算法原理及其python實(shí)現(xiàn)
遺傳算法的基本運(yùn)算過程如下:

  • 初始化編碼:設(shè)置最大進(jìn)化代數(shù)T_max、選擇概率、交叉概率、變異概率、隨機(jī)生成m個(gè)染色體的群體,每個(gè)染色體的編碼對(duì)于一個(gè)可行的路徑(如6個(gè)城市,[1,3,2,6,4,5]就是一條可行路徑)
  • 適應(yīng)度函數(shù):對(duì)每一個(gè)染色體 Xk,其個(gè)體適應(yīng)度函數(shù)設(shè)置為 f(Xk)=1/Dk ,其中Dk 表示該條路徑的總長(zhǎng)度。
  • 選擇:將舊群體中的染色體以一定概率選擇到新群體,每條染色體選中的概率與對(duì)應(yīng)的適應(yīng)度函數(shù)只相對(duì)應(yīng),本文采用隨機(jī)遍歷選擇。
  • 交叉:在交叉概率的控制下,對(duì)選擇群體中的個(gè)體進(jìn)行兩兩交叉。
  • 變異:在變異概率的控制下,對(duì)單個(gè)染色體隨機(jī)交換兩個(gè)點(diǎn)的位置
  • 進(jìn)化逆轉(zhuǎn):將選擇的染色體隨機(jī)選擇兩個(gè)位置r1:r2 ,將 r1:r2 的元素翻轉(zhuǎn)為 r2:r1 ,如果翻轉(zhuǎn)后的適應(yīng)度更高,則替換原染色體,否則不變。
  • 重插:選擇的子代與父代結(jié)合,形成新的種群,循環(huán)操作
  • 流程圖如下

    或者

    代碼

    from math import floor import numpy as np import matplotlib.pyplot as plt # 導(dǎo)入所需要的庫(kù)class Gena_TSP(object):def __init__(self ,data ,maxgen=200 ,size_pop=200 ,cross_prob=0.9 ,pmuta_prob=0.01 ,select_prob=0.8):self.maxgen = maxgen # 最大迭代次數(shù)self.size_pop = size_pop # 群體個(gè)數(shù)self.cross_prob = cross_prob # 交叉概率self.pmuta_prob = pmuta_prob # 變異概率self.select_prob = select_prob # 選擇概率self.data = data # 城市的左邊數(shù)據(jù)self.num =len(data) # 城市個(gè)數(shù) 對(duì)應(yīng)染色體長(zhǎng)度# 距離矩陣n*n, 第[i,j]個(gè)元素表示城市i到j(luò)距離matrix_dis函數(shù)見下文self.matrix_distance = self.matrix_dis()# 通過選擇概率確定子代的選擇個(gè)數(shù)self.select_num = max(floor(self.size_pop * self.select_prob + 0.5), 2)# 父代和子代群體的初始化(不直接用np.zeros是為了保證單個(gè)染色體的編碼為整數(shù),np.zeros對(duì)應(yīng)的數(shù)據(jù)類型為浮點(diǎn)型)self.chrom = np.array([0] * self.size_pop * self.num).reshape(self.size_pop, self.num)#父 print(chrom.shape)(200, 14)self.sub_sel = np.array([0] * self.select_num * self.num).reshape(self.select_num, self.num)#子 (160, 14)# 存儲(chǔ)群體中每個(gè)染色體的路徑總長(zhǎng)度,對(duì)應(yīng)單個(gè)染色體的適應(yīng)度就是其倒數(shù) #print(fitness.shape)#(200,)self.fitness = np.zeros(self.size_pop)self.best_fit = []##最優(yōu)距離self.best_path = []#最優(yōu)路徑# 計(jì)算城市間的距離函數(shù) n*n, 第[i,j]個(gè)元素表示城市i到j(luò)距離def matrix_dis(self):res = np.zeros((self.num, self.num))for i in range(self.num):for j in range(i + 1, self.num):res[i, j] = np.linalg.norm(self.data[i, :] - self.data[j, :])#求二階范數(shù) 就是距離公式res[j, i] = res[i, j]return res# 隨機(jī)產(chǎn)生初始化群體函數(shù)def rand_chrom(self):rand_ch = np.array(range(self.num)) ## num 城市個(gè)數(shù) 對(duì)應(yīng)染色體長(zhǎng)度 =14for i in range(self.size_pop):#size_pop # 群體個(gè)數(shù) 200np.random.shuffle(rand_ch)#打亂城市染色體編碼self.chrom[i, :] = rand_chself.fitness[i] = self.comp_fit(rand_ch)# 計(jì)算單個(gè)染色體的路徑距離值,可利用該函數(shù)更新fittnessdef comp_fit(self, one_path):res = 0for i in range(self.num - 1):res += self.matrix_distance[one_path[i], one_path[i + 1]] #matrix_distance n*n, 第[i,j]個(gè)元素表示城市i到j(luò)距離res += self.matrix_distance[one_path[-1], one_path[0]]#最后一個(gè)城市 到起點(diǎn)距離return res# 路徑可視化函數(shù)def out_path(self, one_path):res = str(one_path[0] + 1) + '-->'for i in range(1, self.num):res += str(one_path[i] + 1) + '-->'res += str(one_path[0] + 1) + '\n'print(res)# 子代選取,根據(jù)選中概率與對(duì)應(yīng)的適應(yīng)度函數(shù),采用隨機(jī)遍歷選擇方法def select_sub(self):fit = 1. / (self.fitness) # 適應(yīng)度函數(shù)cumsum_fit = np.cumsum(fit)#累積求和 a = np.array([1,2,3]) b = np.cumsum(a) b=1 3 6pick = cumsum_fit[-1] / self.select_num * (np.random.rand() + np.array(range(self.select_num)))#select_num 為子代選擇個(gè)數(shù) 160i, j = 0, 0index = []while i < self.size_pop and j < self.select_num:if cumsum_fit[i] >= pick[j]:index.append(i)j += 1else:i += 1self.sub_sel = self.chrom[index, :]#chrom 父# 交叉,依概率對(duì)子代個(gè)體進(jìn)行交叉操作def cross_sub(self):if self.select_num % 2 == 0:#select_num160num = range(0, self.select_num, 2)else:num = range(0, self.select_num - 1, 2)for i in num:if self.cross_prob >= np.random.rand():self.sub_sel[i, :], self.sub_sel[i + 1, :] = self.intercross(self.sub_sel[i, :], self.sub_sel[i + 1, :])def intercross(self, ind_a, ind_b):#ind_a,ind_b 父代染色體 shape=(1,14) 14=14個(gè)城市r1 = np.random.randint(self.num)#在num內(nèi)隨機(jī)生成一個(gè)整數(shù) ,num=14.即隨機(jī)生成一個(gè)小于14的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果r1==r2r2 = np.random.randint(self.num)#r2重新生成left, right = min(r1, r2), max(r1, r2)#left 為r1,r2小值 ,r2為大值ind_a1 = ind_a.copy()#父親ind_b1 = ind_b.copy()# 母親for i in range(left, right + 1):ind_a2 = ind_a.copy()ind_b2 = ind_b.copy()ind_a[i] = ind_b1[i]#交叉 (即ind_a (1,14) 中有個(gè)元素 和ind_b互換ind_b[i] = ind_a1[i]x = np.argwhere(ind_a == ind_a[i])y = np.argwhere(ind_b == ind_b[i])"""下面的代碼意思是 假如 兩個(gè)父輩的染色體編碼為【1234】,【4321】 交叉后為【1334】,【4221】交叉后的結(jié)果是不滿足條件的,重復(fù)個(gè)數(shù)為2個(gè)需要修改為【1234】【4321】(即修改會(huì)來"""if len(x) == 2:ind_a[x[x != i]] = ind_a2[i]#查找ind_a 中元素=- ind_a[i] 的索引if len(y) == 2:ind_b[y[y != i]] = ind_b2[i]return ind_a, ind_b# 變異模塊 在變異概率的控制下,對(duì)單個(gè)染色體隨機(jī)交換兩個(gè)點(diǎn)的位置。def mutation_sub(self):for i in range(self.select_num):#遍歷每一個(gè) 選擇的子代if np.random.rand() <= self.cross_prob:#如果隨機(jī)數(shù)小于變異概率r1 = np.random.randint(self.num)#隨機(jī)生成小于num==14 的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果相同r2 = np.random.randint(self.num)#r2再生成一次self.sub_sel[i, [r1, r2]] = self.sub_sel[i, [r2, r1]]#隨機(jī)交換兩個(gè)點(diǎn)的位置。# 進(jìn)化逆轉(zhuǎn) 將選擇的染色體隨機(jī)選擇兩個(gè)位置r1:r2 ,將 r1:r2 的元素翻轉(zhuǎn)為 r2:r1 ,如果翻轉(zhuǎn)后的適應(yīng)度更高,則替換原染色體,否則不變def reverse_sub(self):for i in range(self.select_num):#遍歷每一個(gè) 選擇的子代r1 = np.random.randint(self.num)#隨機(jī)生成小于num==14 的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果相同r2 = np.random.randint(self.num)#r2再生成一次left, right = min(r1, r2), max(r1, r2)#left取r1 r2中小值,r2取大值sel = self.sub_sel[i, :].copy()#sel 為父輩染色體 shape=(1,14)sel[left:right + 1] = self.sub_sel[i, left:right + 1][::-1]#將染色體中(r1:r2)片段 翻轉(zhuǎn)為(r2:r1)if self.comp_fit(sel) < self.comp_fit(self.sub_sel[i, :]):#如果翻轉(zhuǎn)后的適應(yīng)度小于原染色體,則不變self.sub_sel[i, :] = sel# 子代插入父代,得到相同規(guī)模的新群體def reins(self):index = np.argsort(self.fitness)[::-1]#替換最差的(倒序)self.chrom[index[:self.select_num], :] = self.sub_sel#路徑坐標(biāo) data = np.array([16.47,96.10,16.47,94.44,20.09,92.54,22.39,93.37,25.23,97.24,22.00,96.05,20.47,97.02,17.20,96.29,16.30,97.38,14.05,98.12,16.53,97.38,21.52,95.59,19.41,97.13,20.09,92.55]).reshape(14,2) def main(data):Path_short = Gena_TSP(data) # 根據(jù)位置坐標(biāo),生成一個(gè)遺傳算法類Path_short.rand_chrom() # 初始化父類## 繪制初始化的路徑圖fig, ax = plt.subplots()x = data[:, 0]y = data[:, 1]ax.scatter(x, y, linewidths=0.1)for i, txt in enumerate(range(1, len(data) + 1)):ax.annotate(txt, (x[i], y[i]))res0 = Path_short.chrom[0]x0 = x[res0]y0 = y[res0]for i in range(len(data) - 1):plt.quiver(x0[i], y0[i], x0[i + 1] - x0[i], y0[i + 1] - y0[i], color='r', width=0.005, angles='xy', scale=1,scale_units='xy')plt.quiver(x0[-1], y0[-1], x0[0] - x0[-1], y0[0] - y0[-1], color='r', width=0.005, angles='xy', scale=1,scale_units='xy')plt.show()print('初始染色體的路程: ' + str(Path_short.fitness[0]))# 循環(huán)迭代遺傳過程for i in range(Path_short.maxgen):Path_short.select_sub() # 選擇子代Path_short.cross_sub() # 交叉Path_short.mutation_sub() # 變異Path_short.reverse_sub() # 進(jìn)化逆轉(zhuǎn)Path_short.reins() # 子代插入# 重新計(jì)算新群體的距離值for j in range(Path_short.size_pop):Path_short.fitness[j] = Path_short.comp_fit(Path_short.chrom[j, :])# 每隔三十步顯示當(dāng)前群體的最優(yōu)路徑index = Path_short.fitness.argmin()if (i + 1) % 30 == 0:print('第' + str(i + 1) + '步后的最短的路程: ' + str(Path_short.fitness[index]))print('第' + str(i + 1) + '步后的最優(yōu)路徑:')Path_short.out_path(Path_short.chrom[index, :]) # 顯示每一步的最優(yōu)路徑# 存儲(chǔ)每一步的最優(yōu)路徑及距離Path_short.best_fit.append(Path_short.fitness[index])Path_short.best_path.append(Path_short.chrom[index, :])res1 = Path_short.chrom[0]x0 = x[res1]y0 = y[res1]for i in range(len(data) - 1):plt.quiver(x0[i], y0[i], x0[i + 1] - x0[i], y0[i + 1] - y0[i], color='r', width=0.005, angles='xy', scale=1,scale_units='xy')plt.quiver(x0[-1], y0[-1], x0[0] - x0[-1], y0[0] - y0[-1], color='r', width=0.005, angles='xy', scale=1,scale_units='xy')plt.show()return Path_short # 返回遺傳算法結(jié)果類Path_short=main(data) print(Path_short)

    初始

    最終

    講解

    計(jì)算城市間的距離函數(shù)

    # 計(jì)算城市間的距離函數(shù) n*n, 第[i,j]個(gè)元素表示城市i到j(luò)距離def matrix_dis(self):res = np.zeros((self.num, self.num))for i in range(self.num):for j in range(i + 1, self.num):res[i, j] = np.linalg.norm(self.data[i, :] - self.data[j, :])#求二階范數(shù) 就是距離公式res[j, i] = res[i, j]return res

    隨機(jī)產(chǎn)生初始化群體函數(shù)

    # 隨機(jī)產(chǎn)生初始化群體函數(shù)def rand_chrom(self):rand_ch = np.array(range(self.num)) ## num 城市個(gè)數(shù) 對(duì)應(yīng)染色體長(zhǎng)度 =14for i in range(self.size_pop):#size_pop # 群體個(gè)數(shù) 200np.random.shuffle(rand_ch)#打亂城市染色體編碼self.chrom[i, :] = rand_chself.fitness[i] = self.comp_fit(rand_ch)

    計(jì)算單個(gè)染色體的路徑距離值,可利用該函數(shù)更新self.fittness

    def comp_fit(self, one_path):res = 0for i in range(self.num - 1):res += self.matrix_distance[one_path[i], one_path[i + 1]] #matrix_distance n*n, 第[i,j]個(gè)元素表示城市i到j(luò)距離res += self.matrix_distance[one_path[-1], one_path[0]]#最后一個(gè)城市 到起點(diǎn)距離return res

    子代選取,根據(jù)選中概率與對(duì)應(yīng)的適應(yīng)度函數(shù),采用隨機(jī)遍歷選擇方法

    def select_sub(self):fit = 1. / (self.fitness) # 適應(yīng)度函數(shù)cumsum_fit = np.cumsum(fit)#累積求和 a = np.array([1,2,3]) b = np.cumsum(a) b=1 3 6pick = cumsum_fit[-1] / self.select_num * (np.random.rand() + np.array(range(self.select_num)))#select_num 為子代選擇個(gè)數(shù) 160i, j = 0, 0index = []while i < self.size_pop and j < self.select_num:if cumsum_fit[i] >= pick[j]:index.append(i)j += 1else:i += 1self.sub_sel = self.chrom[index, :]#chrom 父

    交叉,依概率對(duì)子代個(gè)體進(jìn)行交叉操作

    def cross_sub(self):if self.select_num % 2 == 0:#select_num160num = range(0, self.select_num, 2)else:num = range(0, self.select_num - 1, 2)for i in num:if self.cross_prob >= np.random.rand():self.sub_sel[i, :], self.sub_sel[i + 1, :] = self.intercross(self.sub_sel[i, :], self.sub_sel[i + 1, :])def intercross(self, ind_a, ind_b):#ind_a,ind_b 父代染色體 shape=(1,14) 14=14個(gè)城市r1 = np.random.randint(self.num)#在num內(nèi)隨機(jī)生成一個(gè)整數(shù) ,num=14.即隨機(jī)生成一個(gè)小于14的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果r1==r2r2 = np.random.randint(self.num)#r2重新生成left, right = min(r1, r2), max(r1, r2)#left 為r1,r2小值 ,r2為大值ind_a1 = ind_a.copy()#父親ind_b1 = ind_b.copy()# 母親for i in range(left, right + 1):ind_a2 = ind_a.copy()ind_b2 = ind_b.copy()ind_a[i] = ind_b1[i]#交叉 (即ind_a (1,14) 中有個(gè)元素 和ind_b互換ind_b[i] = ind_a1[i]x = np.argwhere(ind_a == ind_a[i])y = np.argwhere(ind_b == ind_b[i])"""下面的代碼意思是 假如 兩個(gè)父輩的染色體編碼為【1234】,【4321】 交叉后為【1334】,【4221】交叉后的結(jié)果是不滿足條件的,重復(fù)個(gè)數(shù)為2個(gè)需要修改為【1234】【4321】(即修改會(huì)來"""if len(x) == 2:ind_a[x[x != i]] = ind_a2[i]#查找ind_a 中元素=- ind_a[i] 的索引if len(y) == 2:ind_b[y[y != i]] = ind_b2[i]return ind_a, ind_b

    變異模塊

    # 變異模塊 在變異概率的控制下,對(duì)單個(gè)染色體隨機(jī)交換兩個(gè)點(diǎn)的位置。def mutation_sub(self):for i in range(self.select_num):#遍歷每一個(gè) 選擇的子代if np.random.rand() <= self.cross_prob:#如果隨機(jī)數(shù)小于變異概率r1 = np.random.randint(self.num)#隨機(jī)生成小于num==14 的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果相同r2 = np.random.randint(self.num)#r2再生成一次self.sub_sel[i, [r1, r2]] = self.sub_sel[i, [r2, r1]]#隨機(jī)交換兩個(gè)點(diǎn)的位置。

    進(jìn)化逆轉(zhuǎn)

    # 進(jìn)化逆轉(zhuǎn) 將選擇的染色體隨機(jī)選擇兩個(gè)位置r1:r2 ,將 r1:r2 的元素翻轉(zhuǎn)為 r2:r1 ,如果翻轉(zhuǎn)后的適應(yīng)度更高,則替換原染色體,否則不變def reverse_sub(self):for i in range(self.select_num):#遍歷每一個(gè) 選擇的子代r1 = np.random.randint(self.num)#隨機(jī)生成小于num==14 的數(shù)r2 = np.random.randint(self.num)while r2 == r1:#如果相同r2 = np.random.randint(self.num)#r2再生成一次left, right = min(r1, r2), max(r1, r2)#left取r1 r2中小值,r2取大值sel = self.sub_sel[i, :].copy()#sel 為父輩染色體 shape=(1,14)sel[left:right + 1] = self.sub_sel[i, left:right + 1][::-1]#將染色體中(r1:r2)片段 翻轉(zhuǎn)為(r2:r1)if self.comp_fit(sel) < self.comp_fit(self.sub_sel[i, :]):#如果翻轉(zhuǎn)后的適應(yīng)度小于原染色體,則不變self.sub_sel[i, :] = sel

    子代插入父代,得到相同規(guī)模的新群體

    # 子代插入父代,得到相同規(guī)模的新群體def reins(self):index = np.argsort(self.fitness)[::-1]self.chrom[index[:self.select_num], :] = self.sub_sel


    作者:電氣-余登武

    總結(jié)

    以上是生活随笔為你收集整理的遗传算法求最短路径(旅行商问题)python实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 麻豆 美女 丝袜 人妻 中文 | 国产美女毛片 | 四虎在线看片 | 99国产精品白浆在线观看免费 | 欧美一级特黄aaaaaa大片在线观看 | 久久久久中文字幕亚洲精品 | 国产色网| 青青操网站 | a级无遮挡超级高清-在线观看 | 国产拍拍拍拍拍拍拍拍拍拍拍拍拍 | jizz日本在线播放 | 日韩在线视频在线观看 | 最近中文字幕av | 成年人国产精品 | 99久久久无码国产精品性青椒 | 男人猛吃奶女人爽视频 | 免费的av网址 | 欧美日韩国产亚洲沙发 | 99re在线| 国产剧情一区在线 | 人人妻人人爽一区二区三区 | 中国一级特黄毛片大片 | 欧美性bbw | 亚洲美女在线播放 | 美女流白浆视频 | 变态另类ts人妖一区二区 | 色就是色网站 | 久草免费福利视频 | 精品91久久久久久 | 日韩在线你懂的 | 黄色一级网址 | 国产片网址 | 成人在线视频播放 | 男生女生羞羞网站 | 欧美日韩黄色一区二区 | 国产草草浮力影院 | 日韩精品短片 | 激情宗合 | 在线免费观看国产精品 | 97超碰色 | 在线观看亚洲国产 | 91精品91久久久中77777 | 黄色网av| 日韩精品人妻一区 | 爆操91 | 久久久91精品国产一区二区三区 | 看国产黄色片 | 精品深夜av无码一区二区老年 | 亚洲av无码一区二区三区人 | 免费看日韩av | 国产女人18毛片水真多 | 成人国产精品视频 | 亚洲人成无码www久久久 | 雨宫琴音一区二区三区 | 电影《两个尼姑》免费播放 | 亚洲成人av免费观看 | 亚洲激情一区二区 | 91国产网站 | 亚洲欧美成人综合 | 永久免费av网站 | 美妇av| 亚洲国产视频一区二区三区 | 亚洲国产日韩精品 | 国产一区2 | 日日骑 | 天天干网站 | 亚洲黄色片在线观看 | 成人片免费视频 | 久久精品亚洲无码 | 日本乱淫视频 | 日韩欧美国产电影 | 伊人影院在线视频 | 视频网站在线观看18 | 波多野结衣毛片 | 日本大乳美女 | 片集网 | 成人午夜免费福利视频 | 亚洲男人天堂电影 | 91视频在线 | 女18毛片 | 日韩不卡一区二区 | 激情视频久久 | 欧美a级在线 | 蜜乳av中文字幕 | 光明影院手机版在线观看免费 | 亚洲第一第二区 | 日韩人妻一区二区三区 | 青青草婷婷 | 亚洲一区 在线播放 | 国产毛片不卡 | 欧美一级片网址 | 天天爽天天爽夜夜爽毛片 | 亚洲狼人伊人 | 国产精品亚洲色图 | 中文字幕 人妻熟女 | zzjj国产精品一区二区 | 99免费国产 | 欧美一级色图 | 婷婷色网站|