遗传算法解八数码问题

八数码问题#

八数码游戏(八数码问题)描述为:在 3×3 组成的九宫格棋盘上,摆有八个将牌,每一个将牌都刻有 1-8 八个数码中的某一个数码。棋盘中留有一个空格,允许其周围的某一个将牌向空格移动,这样通过移动将牌就可以不断改变将牌的布局。这种游戏求解的问题是:给定一种初始的将牌布局或结构(称初始状态)和一个目标的布局(称目标状态),问如何移动将牌,实现从初始状态到目标状态的转变。

遗传算法简介#

遗传算法是通过模拟自然界中生物的遗传进化过程,对优化问题的最优解进行搜索的算法。算法维护一个代表问题潜在解的群体,对于群体的进化,算法引入了类似自然进化中选择、交配以及变异等算子。遗传算法搜索全局最优解的过程是一个不断选代的过程,每一次迭代相当于生物进化中的一次循环,直到满足算法的终止条件为止。
在遗传算法中,问题的每个有效解被称为一个“染色体(chromosome)”,相对于群体中的每个生物个体(individual)。染色体的具体形式是一个使用特定编码方式生成的编码串,编码串中的每一个编码单元称为“基因(gene)”。遗传算法通过比较适应值(fitness value)区分染色体的优劣,适应值越大的染色体越优秀,评估函数(evaluation function)用来计算并确定染色体对应的适应值。
为了在迭代中模拟生物进化的过程,遗传算法引入 3 个算子来实现。

算子 功能
选择算子(selection) 按照一定的规则对群体的染色体进行选择,得到父代种群。一般地,越优秀的染色体被选中的次数越多。
交配算子(crossover) 作用于每两个成功交配的染色体,染色体交换各自的部分基因,产生两个子代染色体。子代染色体取代父代染色体进入新种群,而没有交配的染色体则直接进入新种群。
变异算子(mutation) 使新种群进行小概率的变异。染色体发生变异的基因改变数值,得到新的染色体。经过变异的新种群替代原有群体进入下一次进化。

设计思路#

遗传算法的实现主要包含了以下 6 个重要的部分,我们需要为这些重要的部分进行设计,使其可以解决八数码问题。

  1. 个体设计:问题的一个解的表示方式;
  2. 群体的初始化:用于算法进行迭代的初始种群;
  3. 适应度评价:评估各个染色体的适应值,进而区分优劣,常根据问题的优化目标来确定;
  4. 选择算子;
  5. 交叉算子;
  6. 变异算子。

个体设计#

首先是个体设计,由于八数码问题求解过程中的每一步都是数码“0”与其相邻数码交换,方向只有上下左右 4 个方向,因此一共是 4 种行为。我们可以为这 4 种行为进行编码,例如“1”表示数码 0 左移,“2”表示数码 0 “右移”,“3” 表示数码 0 上移,“4”表示数码 0 下移,这样一个可行解就可以表示为一个有多个编码组成的序列。

所以对于 GA 的个体设计可以使用线性表实现,线性表中的每个元素取自于(1,2,3,4)这个集合中,通过遍历这个线性表就可以获得一个数码 0 的移动序列,即可完成基因到表现型的翻译。

适应度评价#

适应度评价方面决定了种群的优化方向,对于八数码问题而言适应度函数需要起到以下 2 个作用:

  1. 判断个体是否是可行解;
  2. 判断个体是否优于其他可行解。

在适应度的值越高表示个体越优秀的情况下,对于第一个作用,可以设置适应度为当前状态为:各个数码已经位于最终状态的个数。例如下图中的中间状态有 1、2、3、7、8 这五个数码已经位于最终状态,因此得到适应度为 5,而达到最优解个体的适应度应该为 9(或 8)。对于数码0是否计入适应度的问题,我认为计不计入都没有太大影响,因为对于一个可行解而言无论 0 是否计入适应度,其他 8 个数码都会在目标状态的位置下。

对于第二个作用,每个可行解中的数码在目标位置的个数是相同的,因此要挑选更好的个体则不能继续用这种度量方式。由于通过更少的步数使八个数码达到目标状态是更好的解,因此可以引入步数作为可行解优劣的度量方式。
得到的适应度计算公式如下,其中 state_matrix 表示某次移动后的状态矩阵,end_state 表示目标状态矩阵,k 为一个正数,count 为某个可行解的步数。步数较少的可行解,k/count 得到的适应度会更大,反之更小,所有的非可行解 k/count 的值直接置为 0 即可。

其他部分#

对于其他部分而言,由于 GA 在八数码问题中是基于一组初始的解法开始搜索,而每一个个体表达后的序列是否是可行解并不可知,因此只需要基于(1,2,3,4)这4个操作码生成随机序列作为初始种群即可。对于操作算子,八数码问题并不设计更为复杂的运算和操作,只要能改变个体的结构即可,因此可以使用原生的交叉、变异和选择算子。

遗传算法流程#

明确了以上重要部分的定义,就可以通过运行遗传算法求解八数码问题了,遗传算法的运行过程如下:

  1. 初始化规模为 N 的群体,其中染色体的每个基因的值随机生成;
  2. 采用评估函数对群体中所有染色体进行评价,计算每个染色体的适应值,保存适应值最大的染色体 Best;
  3. 对群体的染色体进行选择操作,产生规模同样为 N 的种群;
  4. 从种群中选择染色体进行交配,每两个父代染色体交换部分基因,产生两个新的子代染色体进入新种群,没有进行交配的染色体直接复制进入新种群;
  5. 对新种群中染色体的基因进行变异操作,发生变异的基因的数值发生改变,并取代原有染色体进入新群体,未发生变异的染色体直接进入新群体;
  6. 重新计算群体中各个染色体的适应值,若群体的最大适应值大于 Best 的适应值,则用其替代 Best;
  7. 如果 Generation 超过规定的最大进化代数或 Best 达到规定的误差要求,算法结束,否则返回 Step3。

代码编写#

GA 算法基于 Python 的 DEAP 框架实现,关键在于编写适应度函数。注意如果遇到无效的操作码应该要跳过,而不是直接认为个体无效,这样可以使可行解出现得更容易。

Copy Highlighter-hljs
# -*- coding: utf-8 -*- """ Created on Tue Mar 15 13:47:16 2022 @author: 12207 """ import random import numpy from deap import creator, base, tools, algorithms #起始状态矩阵 init_matrix = [[7, 2, 4], [5, 0, 6], [8, 3, 1]] #目标状态矩阵 end_state = [[1, 2, 3], [4, 5, 6], [7, 8, 0]] # 复制状态 def CopyState(state): s = [] for i in state: s.append(i[:]) return s # 获取空格的位置 def GetSpace(state): for x in range(len(state)): for y in range(len(state[x])): if state[x][y] == 0: return x, y # 测试求解八数码问题 def test(individual, output = False): # 保存 0 坐标和复制一份初始状态矩阵 x, y = GetSpace(init_matrix) state_matrix = CopyState(init_matrix) # 利用个体求解问题 action = [] for i in range(len(individual)): flag = 0 #左移 if individual[i] == 0: if y - 1 >= 0: state_matrix[x][y] = state_matrix[x][y - 1] state_matrix[x][y - 1] = 0 y = y - 1 action.append("左移") flag = 1 else: continue #右移 elif individual[i] == 1: if y + 1 < len(state_matrix[0]): state_matrix[x][y] = state_matrix[x][y + 1] state_matrix[x][y + 1] = 0 y = y + 1 action.append("右移") flag = 1 else: continue #上移 elif individual[i] == 2: if x - 1 >= 0: state_matrix[x][y] = state_matrix[x - 1][y] state_matrix[x - 1][y] = 0 x = x - 1 action.append("上移") flag = 1 else: continue #下移 else: if x + 1 < len(state_matrix[0]): state_matrix[x][y] = state_matrix[x + 1][y] state_matrix[x + 1][y] = 0 x = x + 1 action.append("下移") flag = 1 else: continue #记录行动 if output == True: if flag == 1: print("第" + str(len(action)) + "次行动:" + action[-1]) for l in range(len(state_matrix)): print(state_matrix[l]) print() #检查是否满足可行解 fitness = 0 for j in range(len(state_matrix)): for k in range(len(state_matrix[0])): if state_matrix[j][k] == end_state[j][k]: fitness += 1 if fitness == len(state_matrix) * len(state_matrix[0]): fitness += 100 / len(action) break #输出结果 if output == True: print("共需要:" + str(len(action)) + " 步") print(action) #返回适应度 return fitness # 适应度函数 def evaluate(individual): return test(individual), # 定义问题和个体 creator.create("FitnessMax", base.Fitness, weights=(1.0,)) creator.create("Individual", list, fitness=creator.FitnessMax) # 注册个体和种群 toolbox = base.Toolbox() toolbox.register("attr_bool", random.randint, 0, 3) toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, n = 100) toolbox.register("population", tools.initRepeat, list, toolbox.individual) # 注册操作算子 toolbox.register("evaluate", evaluate) toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) toolbox.register("select", tools.selTournament, tournsize=3) # 定义迭代数和精英数 pop = toolbox.population(n = 800) hof = tools.HallOfFame(1) # 设置显示的迭代信息 stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", numpy.mean) stats.register("std", numpy.std) stats.register("min", numpy.min) stats.register("max", numpy.max) # 运行GA pop, log = algorithms.eaSimple(pop, toolbox, cxpb=0.7, mutpb=0.5, ngen = 150, stats=stats, halloffame=hof, verbose=True) # 取到一次迭代的最优个体 best_ind = tools.selBest(pop, 1)[0] print("Best individual is %s" % (best_ind.fitness.values)) # 用该个体求解八数码问题 test(best_ind, True)

实验结果#

参数设置#

遗传算法涉及到多个超参数,对于不同参数的设置都会影响 GA 是否能求得可行解,以及可行解是否能逼近最优解。 GA 涉及到的参数和本次实验使用的设置如下:

参数名 作用 设置
个体长度 一个个体包含的操作码数量 100
独立概率 每个个体发生变异的概率 5%
选择次数 选择操作时操作的次数 3
种群大小 种群中包含的个体数量 800
精英数量 精英保留时保留的精英数量 1
交叉概率 种群发生交叉操作的概率 70%
变异概率 种群发生变异操作的概率 50%
迭代次数 GA运行的代数 150

这些参数的设置是通过多次实验得到的,实验证明这样设置参数更容易获得可行解,且可行解更容易是最优解。

  1. 对于个体长度而言太长或太短都不适合,太短则操作码序列不易组合成一个可行解,太长则操作码序列中的大量基因都会成为无效基因,影响交叉变异操作;
  2. 对于种群而言,可以稍微设置的大一些,因为种群大小越大,个体类型越丰富,种群中越容易出现可行解,但是种群大小如果太大则会影响算法运行的时间;
  3. 对于迭代次数而言如果设置得太小,则很有可能在找到一个可行解之前就停止迭代导致无解,如果设置过大则会在求得可行解并完成优化后继续迭代,导致运行时间过长;
  4. 其他参数我认为需要通过实验来观察他们对算法的影响,以调制一个相对较好的参数。

求解问题#

经过多次实验后,GA 可以对如下八数码问题求得20步(最优解)、22 步、24 步、26 步和无解等多种可行解,由于参数设置合理出现前 3 种解的概率更高。
其中 20 步解的 GA 迭代过程和算法模拟的过程如下:

Copy Highlighter-hljs
gen nevals avg std min max 0 800 0.916154 1.02216 0 10.9231 1 675 1.15125 1.01038 0 6 2 697 1.30375 1.059 0 6 3 678 1.50375 1.13247 0 6 4 678 1.66625 1.16184 0 6 5 716 1.71875 1.12457 0 6 6 676 1.90875 1.15344 0 6 7 693 2.015 1.13238 0 6 8 693 2.09875 1.21099 0 6 9 658 2.23625 1.20952 0 6 10 664 2.335 1.31919 0 6 11 677 2.34 1.29688 0 6 12 659 2.32375 1.27532 0 6 13 700 2.26125 1.27201 0 6 14 677 2.29716 1.35114 0 10.7241 15 661 2.37966 1.35083 0 10.7241 16 681 2.34841 1.38519 0 10.7241 17 683 2.38125 1.38145 0 6 18 668 2.37 1.33439 0 6 19 673 2.48424 1.31709 0 10.3889 20 661 2.47597 1.41841 0 10.3889 21 677 2.42424 1.3745 0 10.3889 22 699 2.38924 1.3812 0 10.3889 23 681 2.4875 1.3729 0 6 24 680 2.51125 1.4124 0 6 25 673 2.56583 1.39238 0 10.6667 26 680 2.51606 1.34411 0 10.8519 27 691 2.53238 1.5046 0 10.8519 28 677 2.61463 1.42061 0 10.8519 29 681 2.66625 1.38559 0 6 30 686 2.735 1.4568 0 7 31 689 2.7725 1.45026 0 6 32 678 2.74625 1.50062 0 6 33 664 2.85625 1.54534 0 7 34 679 2.97125 1.5868 0 7 35 690 3.0375 1.54874 0 7 36 683 3.06966 1.59835 0 10.7241 37 682 3.17181 1.627 0 10.7241 38 676 3.23285 1.68392 0 10.8519 39 692 3.28214 1.74118 0 10.7241 40 664 3.38493 1.78097 0 10.7241 41 694 3.4483 1.93238 0 11 42 678 3.41232 1.92737 0 11 43 658 3.49972 1.94429 0 10.9231 44 661 3.51843 1.80648 0 10.7857 45 690 3.47305 1.85472 0 11.0833 46 713 3.47086 1.78452 0 10.7241 47 672 3.59817 1.92064 0 10.7857 48 691 3.73408 1.85666 0 11.1739 49 674 3.67482 1.89536 0 11.1739 50 673 3.80356 1.96122 0 10.7857 51 700 3.80797 2.07383 0 11.1739 52 674 3.90646 2.09275 0 11.1739 53 674 4.06944 2.07941 0 10.9231 54 686 4.12545 2.34007 0 10.9231 55 688 4.15162 2.42984 0 10.9231 56 681 4.35468 2.5445 0 10.9231 57 691 4.54398 2.67036 0 11.0833 58 670 4.71895 2.89572 0 11.0833 59 692 4.86082 3.0268 0 11.1739 60 687 4.86067 3.02529 0 11.1739 61 678 5.20179 3.1747 0 11.5 62 677 5.38734 3.28693 0 11.1739 63 693 5.43769 3.42671 0 11.0833 64 683 5.85496 3.61262 0 11.0833 65 700 6.04815 3.62355 0 11.1739 66 681 6.35203 3.55131 0 11.2727 67 695 6.35581 3.63976 0 11.1739 68 669 6.68934 3.66771 0 11.2727 69 676 6.85206 3.63175 0 11.1739 70 677 7.02204 3.73915 0 11.2727 71 672 7.05675 3.73708 0 11.2727 72 671 7.40174 3.6965 0 11.2727 73 691 7.2454 3.73567 0 11.381 74 703 7.37047 3.81093 0 11.381 75 678 7.72293 3.73864 0 11.6316 76 665 7.74398 3.8379 0 11.6316 77 697 7.65846 3.89477 0 11.7778 78 670 8.10184 3.71352 0 11.9412 79 679 7.87819 3.93109 0 12.3333 80 693 7.91455 3.88636 0 11.9412 81 664 8.08672 3.92568 0 12.3333 82 681 8.00442 3.9587 0 12.3333 83 669 8.17642 3.97659 0 12.3333 84 684 8.33876 3.94409 0 12.3333 85 693 8.39025 3.97392 0 12.5714 86 655 8.61277 3.99659 0 12.5714 87 653 8.58687 4.0956 0 12.5714 88 698 8.75961 3.99942 0 13.1667 89 674 8.64706 4.07755 0 13.5455 90 682 8.70197 4.14737 0 13.1667 91 678 8.5173 4.24908 0 13.1667 92 683 8.68691 4.26711 0 13.5455 93 685 8.5834 4.31516 0 13.5455 94 690 8.73941 4.31766 0 13.5455 95 661 8.78165 4.36963 0 13.5455 96 677 8.85828 4.43163 0 13.5455 97 655 9.17691 4.3403 0 14 98 683 9.21458 4.35707 0 14 99 677 9.18711 4.43829 0 14 100 687 9.36876 4.41648 0 14 101 690 9.03331 4.65563 0 14 102 671 9.29202 4.56312 0 14 103 667 9.18334 4.6617 0 14 104 682 9.52724 4.56026 0 14 105 675 9.22975 4.70255 0 14 106 696 9.39653 4.56519 0 14 107 664 9.78237 4.5261 0 14 108 691 9.44421 4.72645 0 14 109 691 9.51576 4.70129 0 14 110 675 9.60297 4.72857 0 14 111 689 9.58822 4.71084 0 14 112 672 9.8205 4.80112 0 14 113 692 9.78278 4.8189 0 14 114 688 10.0249 4.70473 0 14 115 671 9.80663 4.81124 0 14 116 678 9.87802 4.9157 0 14 117 678 9.44586 4.97813 0 14 118 703 9.76003 4.88581 0 14 119 689 9.91857 4.86126 0 14 120 698 9.67992 4.91348 0 14 121 690 9.68896 4.85831 0 14 122 680 9.4835 4.98717 0 14 123 652 9.75117 4.92572 0 14 124 660 9.90767 4.80053 0 14 125 678 9.35005 4.9746 0 14 126 680 9.34913 4.93231 0 14 127 689 9.66326 4.91036 0 14 128 676 9.68926 4.91103 0 14 129 701 9.58734 4.9814 0 14 130 671 9.86524 4.89669 0 14 131 684 9.73642 4.84656 0 14 132 678 9.66712 4.94382 0 14 133 683 9.76349 4.77846 0 14 134 639 10.1327 4.68325 0 14 135 646 10.1052 4.81449 0 14 136 672 9.68233 4.97427 0 14 137 693 9.89786 4.81054 0 14 138 685 9.75015 4.91675 0 14 139 689 9.66459 4.96552 0 14 140 682 9.68376 4.91367 0 14 141 676 9.93599 4.75792 0 14 142 673 9.70179 4.85661 0 14 143 693 9.64158 4.83251 0 14 144 675 9.76849 4.76896 0 14 145 686 9.67357 4.8312 0 14 146 663 9.51975 4.81826 0 14 147 677 9.81509 4.75262 0 14 148 673 9.89897 4.75189 0 14 149 679 10.2556 4.62767 0 14 150 682 9.95908 4.76826 0 14 Best individual is 14.0

求得的最优个体转换为操作码序列,然后进行求解的过程如下:

Copy Highlighter-hljs
['下移', '右移', '上移', '左移', '左移', '上移', '右移', '右移', '下移', '左移', '下移', '左移', '上移', '右移', '上移', '左移', '下移', '右移', '右移', '下移']1次行动:下移 [7, 2, 4] [5, 3, 6] [8, 0, 1]2次行动:右移 [7, 2, 4] [5, 3, 6] [8, 1, 0]3次行动:上移 [7, 2, 4] [5, 3, 0] [8, 1, 6]4次行动:左移 [7, 2, 4] [5, 0, 3] [8, 1, 6]5次行动:左移 [7, 2, 4] [0, 5, 3] [8, 1, 6]6次行动:上移 [0, 2, 4] [7, 5, 3] [8, 1, 6]7次行动:右移 [2, 0, 4] [7, 5, 3] [8, 1, 6]8次行动:右移 [2, 4, 0] [7, 5, 3] [8, 1, 6]9次行动:下移 [2, 4, 3] [7, 5, 0] [8, 1, 6]10次行动:左移 [2, 4, 3] [7, 0, 5] [8, 1, 6]11次行动:下移 [2, 4, 3] [7, 1, 5] [8, 0, 6]12次行动:左移 [2, 4, 3] [7, 1, 5] [0, 8, 6]13次行动:上移 [2, 4, 3] [0, 1, 5] [7, 8, 6]14次行动:右移 [2, 4, 3] [1, 0, 5] [7, 8, 6]15次行动:上移 [2, 0, 3] [1, 4, 5] [7, 8, 6]16次行动:左移 [0, 2, 3] [1, 4, 5] [7, 8, 6]17次行动:下移 [1, 2, 3] [0, 4, 5] [7, 8, 6]18次行动:右移 [1, 2, 3] [4, 0, 5] [7, 8, 6]19次行动:右移 [1, 2, 3] [4, 5, 0] [7, 8, 6]20次行动:下移 [1, 2, 3] [4, 5, 6] [7, 8, 0] 共需要:20

十五数码求解#

同时我也顺便做了 15 数码问题的实验,设置的参数如下所示:

参数名 作用 设置
个体长度 一个个体包含的操作码数量 80
独立概率 每个个体发生变异的概率 5%
选择次数 选择操作时操作的次数 3
种群大小 种群中包含的个体数量 500
精英数量 精英保留时保留的精英数量 1
交叉概率 种群发生交叉操作的概率 70%
变异概率 种群发生变异操作的概率 50%
迭代次数 GA运行的代数 100

经过多次实验后,GA 可以对如下十五数码问题求得 14 步(最优解)、16 步、18 步、20 步和无解等多种可行解,由于参数设置合理出现前3种解的概率更高。

其中 14 步解的 GA 迭代过程如下:

Copy Highlighter-hljs
gen nevals avg std min max 0 500 2.804 1.89778 0 10 1 455 3.61 2.00347 0 10 2 406 4.226 2.01368 0 13 3 420 4.55 2.16876 0 13 4 432 4.74 2.27253 0 13 5 430 5.136 2.17566 0 14 6 420 5.396 2.24481 0 14 7 418 5.96 2.43524 0 14 8 411 6.176 2.59943 1 14 9 418 6.532 2.63685 0 13 10 423 6.82273 2.85749 0 17.8519 11 434 7.0797 2.8077 0 17.8519 12 431 7.13312 2.9915 0 17.9231 13 433 7.59525 3.03271 0 17.9231 14 430 7.8597 2.91932 1 18 15 416 8.16896 3.15923 1 18 16 413 8.7058 3.12672 0 18.381 17 421 8.9332 3.02184 1 18.1739 18 428 9.03772 3.27725 1 18.5 19 423 9.43106 3.19378 1 18.6316 20 425 9.82126 3.17837 1 18.6316 21 415 10.5461 3.16456 2 18.5 22 428 10.7476 3.35155 2 18.5 23 438 10.9505 3.47476 1 18.5 24 437 11.074 3.7309 2 18.7778 25 430 11.6376 3.79662 2 18.7778 26 435 11.6367 4.14556 1 18.9412 27 413 11.9898 4.38395 2 18.9412 28 420 12.7597 4.50714 3 18.9412 29 427 13.1177 4.44418 2 19.125 30 435 12.9664 4.72083 2 19.3333 31 442 13.6065 4.39273 2 19.5714 32 413 13.6956 4.51632 2 19.8462 33 418 14.0886 4.50137 3 19.8462 34 428 14.2752 4.6699 2 20.1667 35 409 14.603 4.70739 2 20.1667 36 429 15.054 4.54146 2 20.1667 37 420 15.26 4.69613 2 20.5455 38 424 15.3826 4.6169 3 20.5455 39 425 15.5825 4.86051 2 20.5455 40 415 16.0692 4.80273 3 21 41 432 16.052 4.97239 3 21.5556 42 416 16.252 5.05336 0 21.5556 43 433 16.829 4.79003 4 21.5556 44 428 17.1049 4.70856 4 22.25 45 415 16.8963 5.1402 3 22.25 46 420 17.462 4.86248 4 22.25 47 427 17.1116 5.26254 3 23.1429 48 411 17.6386 5.0697 4 23.1429 49 436 17.6618 5.22843 3 23.1429 50 432 17.94 5.23996 3 23.1429 51 447 18.227 5.34326 2 23.1429 52 446 18.5562 5.25413 4 23.1429 53 419 18.7661 5.19452 4 23.1429 54 453 18.4708 5.42239 4 23.1429 55 412 19.1343 5.11742 5 23.1429 56 429 18.724 5.53154 2 23.1429 57 415 18.9125 5.42473 4 23.1429 58 420 18.7524 5.51772 2 23.1429 59 408 18.4968 5.81073 2 23.1429 60 426 18.8919 5.6346 2 23.1429 61 425 18.6763 5.72745 1 23.1429 62 440 19.0743 5.53242 3 23.1429 63 420 19.4044 5.38224 2 23.1429 64 402 19.0829 5.7189 3 23.1429 65 420 19.1684 5.61303 3 23.1429 66 411 19.6009 5.49468 3 23.1429 67 432 18.8824 5.83395 3 23.1429 68 438 18.9075 5.75353 4 23.1429 69 410 18.7874 5.93363 3 23.1429 70 427 18.9897 5.76009 2 23.1429 71 431 19.4343 5.55504 4 23.1429 72 400 18.8594 6.04564 3 23.1429 73 428 19.015 5.8188 2 23.1429 74 423 19.29 5.80855 3 23.1429 75 442 18.262 6.25965 4 23.1429 76 418 19.2296 5.70333 2 23.1429 77 424 19.1242 5.8113 2 23.1429 78 427 18.8145 6.03968 4 23.1429 79 419 19.3995 5.57845 2 23.1429 80 430 19.2223 5.70262 4 23.1429 81 419 18.751 5.97296 4 23.1429 82 434 19.0121 5.84478 3 23.1429 83 423 18.454 6.19559 2 23.1429 84 417 18.7456 6.03199 3 23.1429 85 431 18.8156 5.93744 2 23.1429 86 435 19.0928 5.76365 3 23.1429 87 436 18.6646 6.15669 3 23.1429 88 405 18.7848 6.0336 1 23.1429 89 424 18.9909 5.88768 2 23.1429 90 437 18.3604 6.302 1 23.1429 91 437 18.605 6.22241 3 23.1429 92 436 18.1165 6.43491 2 23.1429 93 429 18.8608 5.85384 4 23.1429 94 440 18.6587 6.11432 3 23.1429 95 442 18.819 5.90563 3 23.1429 96 424 18.7152 6.09943 2 23.1429 97 415 18.804 6.03523 3 23.1429 98 418 18.543 6.23341 2 23.1429 99 446 18.4038 6.29188 3 23.1429 100 420 19.0295 5.89556 4 23.1429 Best individual is 23.142857142857142

求得的最优个体转换为操作码序列,然后进行求解的过程如下:

Copy Highlighter-hljs
['上移', '右移', '下移', '左移', '左移', '上移', '上移', '上移', '右移', '右移', '下移', '下移', '右移', '下移']1次行动:上移 [5, 1, 2, 4] [9, 6, 3, 8] [13, 0, 10, 11] [14, 15, 7, 12]2次行动:右移 [5, 1, 2, 4] [9, 6, 3, 8] [13, 10, 0, 11] [14, 15, 7, 12]3次行动:下移 [5, 1, 2, 4] [9, 6, 3, 8] [13, 10, 7, 11] [14, 15, 0, 12]4次行动:左移 [5, 1, 2, 4] [9, 6, 3, 8] [13, 10, 7, 11] [14, 0, 15, 12]5次行动:左移 [5, 1, 2, 4] [9, 6, 3, 8] [13, 10, 7, 11] [0, 14, 15, 12]6次行动:上移 [5, 1, 2, 4] [9, 6, 3, 8] [0, 10, 7, 11] [13, 14, 15, 12]7次行动:上移 [5, 1, 2, 4] [0, 6, 3, 8] [9, 10, 7, 11] [13, 14, 15, 12]8次行动:上移 [0, 1, 2, 4] [5, 6, 3, 8] [9, 10, 7, 11] [13, 14, 15, 12]9次行动:右移 [1, 0, 2, 4] [5, 6, 3, 8] [9, 10, 7, 11] [13, 14, 15, 12]10次行动:右移 [1, 2, 0, 4] [5, 6, 3, 8] [9, 10, 7, 11] [13, 14, 15, 12]11次行动:下移 [1, 2, 3, 4] [5, 6, 0, 8] [9, 10, 7, 11] [13, 14, 15, 12]12次行动:下移 [1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 0, 11] [13, 14, 15, 12]13次行动:右移 [1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 11, 0] [13, 14, 15, 12]14次行动:下移 [1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 11, 12] [13, 14, 15, 0] 共需要:14

对比 A* 算法#

由于 A* 算法不属于智能计算算法,无论是算法过程还是启发函数计算都是确定的,因此使用 A* 算法得到的解也是确定的。在八数码问题中,从初始状态到当前状态的代价就用移动的步数表示,从当前状态到目标状态的估计代价就用所有数码与它们的最终位置的曼哈顿距离表示。由于问题规模和八数码问题本身的最优求解策略而言,这种设置下求得的解只有一种且为最优解。
个人认为对于八数码这类规模小、问题复杂度低、具有明确的求解策略的问题,显然 A* 算法更为合适。因为 A* 算法的启发策略很简单,非常契合八数码问题本身,即只需要在有限的搜索空间和有限的搜索能力上,按照明确的求解策略来执行即可得到最优解。
而 GA 则需要为八数码问题设计个体的形式,设计适应度的评估函数,指定相关的操作算子并进行迭代后才能求得可行解,在合适的参数和足够多次的实验下可以求得最优解。这是因为 GA 算法是一个通用的算法框架,只需要对个体和适应度的评估方式进行合理地设计,即可求解最优化问题,其他能求解最优化问题的智能计算算法也可以做到。
同时 GA 进行的是一种对于全局的搜索,它的搜索空间和搜索能力远高于 A* 算法,但是搜索的方式相对而言就显得更加随机,更加盲目。因此对于八数码问题而言反倒不是最优的解法,但是 GA 也可以提供更多的可行解拓展我们对问题的认知,GA 更适合用于对一些 NP 难问题或者一些复杂的最优化问题进行求解。

参考资料#

《计算智能》,张军 詹志辉 等编著,清华大学出版社
DEAP documentation

posted @   乌漆WhiteMoon  阅读(1053)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS