遗传算法解决寻路问题——Python描述

概要

我的上一篇写遗传算法解决排序问题,当中思想借鉴了遗传算法解决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 
  4 MIN = 0
  5 MAX = 9999
  6 WIDTH = 100
  7 HEIGHT = 100
  8 PATH_COUNT = 100
  9 
 10 DIS_1 = 1 / math.sqrt(2)
 11 DIS_2 = 1
 12 
 13 S = 0
 14 D = 0
 15 # 路径
 16 paths = []
 17 # 最优路径
 18 best_path = []
 19 # 迭代次数
 20 ITERATION_COUNT = 10
 21 #
 22 direction_arr = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
 23 
 24 
 25 def is_valid(point):
 26     if point[0] < 0 or point[1] < 0 or point[0] >= WIDTH or point[1] >= HEIGHT:
 27         return False
 28     return True
 29 
 30 
 31 # 计算欧式距离
 32 def distance(p1, p2):
 33     return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
 34 
 35 
 36 # 标号转坐标
 37 def mark2position(mark):
 38     return (mark % WIDTH, int(mark / WIDTH))
 39 
 40 
 41 def position2mark(position):
 42     return position[1] * WIDTH + position[0]
 43 
 44 
 45 # 5 6 7
 46 # 3   4
 47 # 0 1 2
 48 def generate_one_path(start, end):
 49     res = []
 50     res.append(start)
 51 
 52     s = start
 53     target_point = mark2position(end)
 54     dis = distance(mark2position(start), target_point)
 55 
 56     while (s != end):
 57         pos = mark2position(s)
 58         r = random.randint(0, 7)
 59         pos = (pos[0] + direction_arr[r][0], pos[1] + direction_arr[r][1])
 60         temp_dis = distance(pos, target_point)
 61         if is_valid(pos) and temp_dis <= dis:
 62             s = position2mark(pos)
 63             dis = temp_dis
 64             res.append(s)
 65     return res
 66 
 67 
 68 # 初代
 69 def init(count):
 70     res = []
 71     for i in range(0, count):
 72         res.append(generate_one_path(S, D))
 73     return res
 74 
 75 
 76 # 计算一条路径的适应度值
 77 def one_path_fit_val(path):
 78     sm = 0
 79     for i in range(1, len(path)):
 80         w = int(math.fabs(path[i - 1] - path[i]))
 81         if w == 1 or w == WIDTH:
 82             sm += DIS_2
 83         else:
 84             sm += DIS_1
 85     return sm
 86 
 87 
 88 # 计算适应度值
 89 def fitness():
 90     res = []
 91     max_fit = -1
 92     for path in paths:
 93         f = one_path_fit_val(path)
 94         if f > max_fit:
 95             max_fit = f
 96             best_path = path
 97         res.append(f)
 98     return res
 99 
100 
101 # 累计概率
102 def cumulative_probability(fits):
103     res = []
104     sm = sum(fits)
105     temp = fits[0] / sm
106     res.append(temp)
107     for i in range(1, len(fits)):
108         res.append(res[i - 1] + fits[i] / sm)
109     return res
110 
111 
112 # 选择 产生下一代
113 def choose(pArr, count):
114     res = []
115     for i in range(count):
116         p = random.random()
117         for j in range(len(pArr)):
118             if p <= pArr[j]:
119                 res.append(paths[j])
120                 break
121     return res
122 
123 
124 # run point
125 random.seed()
126 S = random.randint(MIN, MAX)
127 D = random.randint(MIN, MAX)
128 while (S == D):
129     D = random.randint(MIN, MAX)
130 
131 # 初代
132 paths = init(PATH_COUNT)
133 
134 fits = fitness()  # 适应度计算
135 pArr = cumulative_probability(fits)  # 累计概率
136 res = choose(pArr, PATH_COUNT)  # 选择
137 
138 for p in res:
139     print(p)

猜你喜欢

转载自www.cnblogs.com/oldBook/p/9900341.html