概要

我的上一篇写遗传算法解决排序问题,当中思想借鉴了遗传算法解决TSP问题,本质上可以认为这是一类问题,就是这样认为:寻找到一个序列X,使F(X)最大。

详解介绍

排序问题:寻找一个序列,使得这个序列的逆序对的倒数最大。

TSP问题:寻找一个序列,使得这个序列的总路径长的倒数最大。

这两个问题有一个共同的特点是,所有的节点都要用上,而使用遗传算法解决排序问题(每一个格子可以认为是一个节点),是需要从众多的节点之中寻找到某些节点构成一个序列X。

序列X必须满足的条件是:

  1. 相邻节点直接邻接
  2. 无重复节点(有重复的相当于走回头路)
  3. 序列的起点和终点必须是已知的点

第一个需要解决的问题是初代如何选择:

  1. 随机选择然后判断是否符合上面的三个条件(垃圾)
  2. 从起点开始随机生成到终点的序列

第二种做法的另一个问题就是随机性太大,可能会走比较长的路(其实也是可以采用的),为了解决这个问题,我才用了A*算法的启发式思维,将当前点和目标点的蔓哈顿距离作为适应度加入到优先队列中。

算法步骤

  1. 将起点加入到优先队列中
  2. 从优先队列中取出顶部顶点p0,将p0加入到Path(路径结果),如果p0是终点结束;
  3. 随机获取其周围的8个点中的一个p1
  4. 比较p0到目标点的曼哈顿距离|p0-target|  和p1到目标点的距离|p1-target|
  5. 如果|p1-target|<|p0-target|并且p1 not in Path, 将p1加入优先队列,p0<-p1;转到2

使用这种策略不仅引入了随机性,而且路径也比较合适,收敛比较快。

选择

这一步比较简单,就是普通的轮盘法就ok

交叉和变异

目前还没有想到策略(后面补充)

代码实现

  1 import random
  2 import math
  3 import copy
  4 from tkinter import *
  5 import tkinter.font as tkFont
  6 import time, threading
  7
  8 WIDTH = 100
  9 HEIGHT = 100
 10 MIN = 0
 11 MAX = WIDTH * HEIGHT - 1
 12
 13 PATH_COUNT = 100
 14 # 交叉概率
 15 cross_p = 0.6
 16 # 变异概率
 17 variation_p = 0.4
 18 # 变异次数
 19 variation_times = 4
 20
 21 DIS_1 = 1.4
 22 DIS_2 = 1
 23
 24 S = 0
 25 D = 0
 26
 27 best_path = []
 28 best_path_index = 0
 29
 30 res_fit = []
 31
 32 # 路径
 33 paths = []
 34 # 最优路径
 35 # 迭代次数
 36 ITERATION_COUNT = 100
 37 #
 38 direction_arr = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
 39
 40
 41 def is_valid(point):
 42     if point[0] < 0 or point[1] < 0 or point[0] >= WIDTH or point[1] >= HEIGHT:
 43         return False
 44     return True
 45
 46
 47 # 计算欧式距离
 48 def distance(p1, p2):
 49     return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
 50
 51
 52 # 标号转坐标
 53 def mark2position(mark):
 54     return (mark % WIDTH, int(mark / WIDTH))
 55
 56
 57 def position2mark(position):
 58     return position[1] * WIDTH + position[0]
 59
 60
 61 # 5 6 7
 62 # 3   4
 63 # 0 1 2
 64 def generate_one_path(start, end):
 65     res = []
 66     res.append(start)
 67
 68     s = start
 69     target_point = mark2position(end)
 70     dis = distance(mark2position(start), target_point)
 71
 72     while (s != end):
 73         pos = mark2position(s)
 74         r = random.randint(0, 7)
 75         pos = (pos[0] + direction_arr[r][0], pos[1] + direction_arr[r][1])
 76         temp_dis = distance(pos, target_point)
 77         if is_valid(pos) and temp_dis <= dis:
 78             s = position2mark(pos)
 79             dis = temp_dis
 80             res.append(s)
 81     return res
 82
 83
 84 # 初代
 85 def init(count):
 86     res = []
 87     for i in range(0, count):
 88         res.append(generate_one_path(S, D))
 89     return res
 90
 91
 92 # 计算一条路径的适应度值
 93 def one_path_fit_val(path):
 94     sm = 0
 95     for i in range(1, len(path)):
 96         w = int(math.fabs(path[i - 1] - path[i]))
 97         if w == 1 or w == WIDTH:
 98             sm += DIS_2
 99         else:
100             sm += DIS_1
101     return MAX / sm
102
103
104 # 计算适应度值
105 def fitness():
106     res = []
107     max_fit = -1
108     global best_path
109     global best_path_index
110
111     temp_best_path = []
112
113     for i in range(len(paths)):
114         f = one_path_fit_val(paths[i])
115         res.append(f)
116         if f > max_fit:
117             max_fit = f
118             temp_best_path = paths[i]
119             best_path_index = i
120     best_path = copy.deepcopy(temp_best_path)
121     res_fit.append(max_fit)
122     return res
123
124
125 # 累计概率
126 def cumulative_probability(fits):
127     res = []
128     sm = sum(fits)
129     temp = fits[0] / sm
130     res.append(temp)
131     for i in range(1, len(fits)):
132         res.append(res[i - 1] + fits[i] / sm)
133     return res
134
135
136 # 选择 产生下一代
137 def choose(pArr, count):
138     res = []
139     for i in range(count):
140         p = random.random()
141         for j in range(len(pArr)):
142             if p <= pArr[j]:
143                 res.append(paths[j])
144                 break
145     return res
146
147
148 def cross_one_times(path1, path2):
149     # 求交集
150     temp = list(set(path1[1:-1]).intersection(set(path2[1:-1])))
151     sz = len(temp)
152     if sz == 0:
153         return (path1, path2)
154     r = random.random()
155     if r > cross_p:
156         index = random.randint(0, sz - 1)
157         e = temp[index]
158         t1 = path1.index(e)
159         t2 = path2.index(e)
160         p1 = path1[:t1]
161         p2 = path2[t2:]
162         p3 = path2[:t2]
163         p4 = path1[t1:]
164         p1.extend(p2)
165         p3.extend(p4)
166         return (p1, p3)
167     else:
168         return (path1, path2)
169
170
171 def cross():
172     n = len(paths)
173     res = []
174     for i in range(1, n, 2):
175         p = cross_one_times(paths[i], paths[i - 1])
176         res.extend(p)
177
178     # 奇数情况
179     if len(res) < n:
180         res.append(paths[n - 1])
181     return res
182
183
184 # 判断三点之间是否联通
185 def is_valid_3_mark(m1, m2, m3):
186     # 重复
187     if m1 == m2 or m1 == m3 or m2 == m3:
188         return False
189     if m2 < MIN or m2 > MAX:
190         return False
191     # 不联通
192     if not (m1 + 1 == m2 or m1 - 1 == m2 or m1 + WIDTH == m2 or m1 - WIDTH == m2
193             or m1 + WIDTH + 1 == m2 or m1 + WIDTH - 1 == m2
194             or m1 - WIDTH + 1 == m2 or m1 - WIDTH - 1 == m2):
195         return False
196     # 不联通
197     if not (m3 + 1 == m2 or m3 - 1 == m2 or m3 + WIDTH == m2 or m3 - WIDTH == m2
198             or m3 + WIDTH + 1 == m2 or m3 + WIDTH - 1 == m2
199             or m3 - WIDTH + 1 == m2 or m3 - WIDTH - 1 == m2):
200         return False
201     return True
202
203
204 def variation_one_times(path):
205     r = random.random()
206     if r < variation_p:
207         return path
208     else:
209         sz = len(path)
210         if sz <= 2:
211             return path
212         # 变异点
213         prob_mark = []
214         var_index = random.randint(1, sz - 2)
215         pre_mark = path[var_index - 1]
216         cnt_mark = path[var_index]
217         next_mark = path[var_index + 1]
218         # 8中情况
219         temp_mark = [cnt_mark + 1, cnt_mark - 1, cnt_mark + WIDTH, cnt_mark - WIDTH, cnt_mark + WIDTH + 1,
220                      cnt_mark + WIDTH - 1, cnt_mark - WIDTH - 1, cnt_mark - WIDTH + 1]
221         for e in temp_mark:
222             if is_valid_3_mark(pre_mark, e, next_mark):
223                 prob_mark.append(e)
224
225         if len(prob_mark) == 0:
226             return path
227         changed_mark = prob_mark[random.randint(0, len(prob_mark) - 1)]
228         path[var_index] = changed_mark
229         return path
230
231
232 def variation():
233     res = paths
234     for i in range(variation_times):
235         temp = []
236         for e in res:
237             temp.append(variation_one_times(e))
238         res = temp
239     return res
240
241
242 def output(g, f):
243     print("第" + str(g) + "代:最优路径:", end="", file=f)
244     print(best_path, end="", file=f)
245     print("适应度: ", end="", file=f)
246     print(fits[best_path_index], file=f)
247     for i, path in enumerate(paths):
248         print(str(i + 1) + ". ", end="", file=f)
249         print(path, end="", file=f)
250         print("适应度值:" + str(fits[i]), file=f)
251
252
253 def mark_screen_position(mark, x_min, y_max):
254     temp_p = mark2position(mark)
255     x = temp_p[0] - x_min
256     y = y_max - temp_p[1]
257     return (x, y)
258
259
260 def show(path, title):
261     canvas_width = 1000
262     point_r = 2
263     show_mark_min_width = 10
264     temp = []
265     for p in path:
266         temp.append(p % 100)
267     x_min = min(temp)
268     x_max = max(temp)
269     temp.clear()
270     for p in path:
271         temp.append(int(p / 100))
272     y_min = min(temp)
273     y_max = max(temp)
274     d = max(x_max - x_min + 1, y_max - y_min + 1)
275     grid_width = int(canvas_width / d)
276     canvas_width = grid_width * d
277     win = Tk()
278     win.title(title)
279     win.geometry(str(canvas_width) + "x" + str(canvas_width) + "+100+100")
280     can = Canvas(win, width=canvas_width, height=canvas_width, bg="white")
281     for i in range(0, canvas_width, grid_width):
282         can.create_line((0, i), (canvas_width, i))
283
284     for i in range(0, canvas_width, grid_width):
285         can.create_line((i, 0), (i, canvas_width))
286     ft = tkFont.Font(root=win, family='Fixdsys', size=int(20 / 4), weight=tkFont.BOLD)
287     if grid_width >= show_mark_min_width:
288         for x in range(0, d):
289             for y in range(0, d):
290                 s = position2mark((x + x_min, y_max - y))
291                 can.create_text(x * grid_width + grid_width / 2, y * grid_width + grid_width / 2, text=s,
292                                 font=ft)
293     sz = len(path)
294     for i in range(0, sz - 1):
295         p1 = mark_screen_position(path[i], x_min, y_max)
296         p2 = mark_screen_position(path[i + 1], x_min, y_max)
297         can.create_line((p1[0] * grid_width + grid_width / 2, p1[1] * grid_width + grid_width / 2),
298                         (p2[0] * grid_width + grid_width / 2, p2[1] * grid_width + grid_width / 2), fill="red", width=3)
299         if i == 0: {
300             can.create_oval(
301                 (p1[0] * grid_width + grid_width / 2 - point_r, p1[1] * grid_width + grid_width / 2 - point_r,
302                  p1[0] * grid_width + grid_width / 2 + point_r, p1[1] * grid_width + grid_width / 2 + point_r),
303                 fill="blue")
304         }
305         can.create_oval((p2[0] * grid_width + grid_width / 2 - point_r, p2[1] * grid_width + grid_width / 2 - point_r,
306                          p2[0] * grid_width + grid_width / 2 + point_r, p2[1] * grid_width + grid_width / 2 + point_r),
307                         fill="blue")
308     can.pack()
309     win.mainloop()
310
311
312 # run point
313 random.seed()
314 S = random.randint(MIN, MAX)
315 D = random.randint(MIN, MAX)
316 while (S == D):
317     D = random.randint(MIN, MAX)
318 g = 1
319 fp = open("1.txt", "w", encoding="utf-8")
320
321 # 初代
322 paths = init(PATH_COUNT)
323 fits = fitness()  # 适应度计算
324 output(g, fp)
325 g = g + 1
326
327 origin_best_path = []
328
329 for i in range(ITERATION_COUNT):
330     pArr = cumulative_probability(fits)  # 累计概率
331     paths = choose(pArr, PATH_COUNT - 1)  # 选择
332     paths = cross()  # 交叉
333     paths = variation()  # 变异
334     paths.append(best_path)
335     if i == 0:
336         origin_best_path = copy.deepcopy(best_path)
337     fits = fitness()  # 适应度计算
338     output(g, fp)
339     g = g + 1
340 fp.flush()
341 fp.close()
342
343 fp = open("2.txt", "w", encoding="utf-8")
344 fp.write("最大适应度值列表:\n")
345 for e in res_fit:
346     fp.write(format(e, ".2f"))
347     fp.write(" ")
348 fp.flush()
349 fp.close()
350
351 t1 = threading.Thread(target=show, args=(origin_best_path, "初代最好的路径"))
352 t2 = threading.Thread(target=show, args=(best_path, "最好的路径"))
353 t1.start()
354 t2.start()
355 t1.join()
356 t2.join()

效果图

图形显示

转载于:https://www.cnblogs.com/oldBook/p/9900341.html

遗传算法解决寻路问题——Python描述相关推荐

  1. 遗传算法解决旅行商问题(Python版)

    完整代码点这里 遗传算法解决旅行商问题(Python版) 一.问题描述 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中 ...

  2. 遗传算法解决TSP问题 Python实现【160行以内代码】

    简述 之前通过遗传算法(Genetic Algorithm )+C++实现解决TSP问题 写了一些基本的原理.并且给出了C++版本代码. 相比于近300行的C++程序,Python只用了160行就解决 ...

  3. GA(遗传算法) 解决TSP问题 Python实现

    TSP:Traveling Salesman Problem GA:Genetic Algorithm Python3.7 1. 第一问最小生成树问题 使用了Prim算法基于Python3.7实现 最 ...

  4. 模拟退火算法解决TSP(python实现 110+行代码)【gif生成】

    简述 代码我是基于我之前写的两篇,一篇是遗传算法TSP的Python实现,一篇是模拟退火算法的解决TSP的C++实现. 模拟退火算法理论+Python解决函数极值+C++实现解决TSP问题 遗传算法解 ...

  5. 遗传算法解决tsp问题(基于python)

    目录 1.遗传算法简要介绍 2.tsp问题简要介绍 3.遗传算法解决tsp问题的几个特殊点 4.源码 1.遗传算法简要介绍 简单来说,遗传算法是用于解决最优化问题的一种搜索算法.其核心基于自然界种群进 ...

  6. 【Python】用蒙特卡洛树搜索(MCTS)解决寻路问题

    像人类一样思考. 文章目录 用蒙特卡洛树搜索(MCTS)解决寻路问题 关于蒙特卡洛树搜索 寻路问题和寻路算法 数据结构与定义 寻路算法的基本假设 权值计算 改进后的权值存储和加权随机策略 测试运行 结 ...

  7. 使用遗传算法解决图着色问题

    使用遗传算法解决图着色问题 图着色 问题描述 应用 解的表示形式 图着色问题中的约束条件 利用python实现问题创建 遗传算法解决图着色问题 常量及遗传算子定义 使用精英主义策略 遗传流程 结果 使 ...

  8. 使用遗传算法解决N皇后问题

    使用遗传算法解决N皇后问题 N皇后问题 解的表示 问题的表示 遗传算法解决N皇后问题 常量及遗传算子定义 使用精英主义策略 遗传流程 结果 N皇后问题 经典的N皇后问题最初被称为八皇后拼图,起源于国际 ...

  9. 遗传算法解决8数码难题——Java

    遗传算法解决8数码难题--Java 什么是遗传算法 什么是8数码难题 解决8数码难题--Java 轮盘赌算法思想 代码优化 参考文章 什么是遗传算法 ​   遗传算法是模拟达尔文生物进化伦的自然选择和 ...

最新文章

  1. LAMP架构介绍、MySQL和MariaDB介绍、MySQL安装
  2. Tomcat web.xml配置参数详解
  3. ckfinder php 配置,php – 在Laravel 5中为CKEditor设置路径以使用CKFinder
  4. SPOJ QTREE5 lct
  5. docker安装mysql数据库映射_Docker安装mysql数据库
  6. PowerCmd(命令行增强工具) 2.2 免费版
  7. mysql中连接和断开数据库_robot framework——连接和断开mysql数据库
  8. MIPI - DVP
  9. Confluence 6 重新获得附件指南
  10. 算法设计与分析基础(三)
  11. 基于R语言的方差分析
  12. 敲电子木鱼微信小程序源码下载+搭建教程
  13. 红队web打点信息收集
  14. HoughCircles()函数 画圆心和圆的轮廓
  15. 操作系统原理与Linux实践教程【第一章 操作系统概论】
  16. 拖拽插件jquery.dad.js
  17. nil Foundation blueprint模块代码解析
  18. Android多人视频聊天应用的开发(一)快速集成
  19. 情人节 玫瑰花表白源码
  20. SpringCloud之Gateway

热门文章

  1. 写一些随感,以此今年金庸先生
  2. Java基础练习题 1-50
  3. OEM、ODM别再混淆了,TCOOP教您轻松辨别
  4. 反向跟单——结果偏见
  5. 期货反向跟单--脚踏两只船与时间管理
  6. 华为推出“换皮肤”服务
  7. uniapp获取微信手机号码
  8. 微信开发者工具C盘占用大的问题
  9. 数据库DB之MySQLOracle
  10. JS设置COOKIE,PHP中处理