人工智能课程设计——八皇后问题的求解算法比较

  • 八皇后问题的求解算法及步骤分析
    • 回溯法——通用的解法
      • 回溯法求解八皇后问题具体步骤为:
    • 爬山法——经典的解法
    • 随机重启爬山法——前进的解法
    • 模拟退火法——他山之石
    • A* 算法——启发式解法
  • 参考文献

最近暑假有些空闲时间,于是把这学期写的一些课程设计记录下来,如果有需要请自取,原创不易,希望能给各位的学习带来一些方便。

八皇后问题的求解算法及步骤分析

回溯法——通用的解法

回溯法被称为一种通用的解题法,它的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法。这种方法适用于解一些组合数相当大的问题。回溯法在问题的解空间树中,是按深度优先策略,从根结点出发去搜索解空间树。当算法搜索至解空间树的任意一点时,首先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其根结点进行回溯;否则,进入该子树,继续按深度优先策略搜索。其核心思想就是走不通则调头,类似于走迷宫 。

回溯法求解八皇后问题具体步骤为:

八个皇后用 q=0,1,2,3,4,5,6,7q=0,1,2,3,4,5,6,7q=0,1,2,3,4,5,6,7来表示,其中第一个皇后放在8*8 矩阵的(0,0)(0,0)(0,0)位置,也就是 q=0,x[q]=0q=0,x[q]=0q=0,x[q]=0 ,这里的 q表示行和皇后q, 表示列。
⑴、在第一行放下第一个皇后之后,再放下一个皇后时是从第二行开始放,此时需要判断皇后放置在第二行的哪一列;
⑵、如果下一个皇后摆放位置与其他皇后位置冲突(即皇后在同一列或同一斜线上),就进行x[q]++x[q]++x[q]++ ,一直找到不发生冲突的位置;
⑶、一直进行判断是否有剩余的皇后或是否发生越界,假如还有剩余的皇后,则进行 ,继续摆放下一个皇后,假如有皇后发生越界,则进行回溯,即 x[q]=−1,q=q−1x[q]=-1,q=q-1x[q]=−1,q=q−1。
检查皇后 是否发生冲突代码:

int check(int q){for(int i=0;i<q;i++){if(x[i]==x[q] || abs(x[i]-x[q])== abs(i-q))//检查皇后摆放位置是否在同一列或同一斜线return 1;return 0;}

关于回溯法的相关代码是用 语言实现的C++C++C++,输出结果为不发生冲突的八皇后各皇后的位置,一共输出有929292 种摆法。

爬山法——经典的解法

爬山法思想虽然简单但是有效,不断去选择最短路径达到目标,将损耗尽可能减小到最低,故被人称为“贪婪算法”。于是算法的核心就是一个简单的循环,不断向值增加的方向持续移动——登高。直到算法到达一个“峰顶”时才终止,这时邻接状态中没有比它的值更高的。
对于爬山法这样的算法人们将它归类于局部搜索算法。有些搜索算法是需要返回从初始状态到目标状态的这条路径作为这个问题的解;而实际中有很多最优化的问题,是不需要知道到达目标的这条路径。它只关心状态本身,只需要算法找到一个符合当前要求的目标状态,那么这个目标状态本身才是问题的解。针对这一类问题我们就可以采用局部搜索算法。
局部算法只需要考虑当前状态与邻接状态,不需考虑全局的状态信息,自然计算量就小很多。但是,它也有一个致命的缺陷——当达到局部极大值时就会卡在这里无路可走,因为在一个局部极大值点的周围邻接点与之相比都不是最优,不管移动到哪一个都只会比原来的更差[5]。

接下来详细分析一下爬山法求解八皇后问题的具体步骤:
⑴、输入八皇后的初始位置信息,计算该位置出现冲突的八皇后数目作为损失最小值;
⑵、按照初始化八皇后位置变化顺序,依次输入变化位置信息,计算该组位置的损失并与上一损失比较,保留损失最小的八皇后位置信息;
⑶、不断循环进行比较,直到找到损失为零的八皇后位置信息,即保证各皇后不会发生冲突的位置信息。

比较八皇后位置信息代码:

best = []
next = self.getNeighbor(self.puzzle)
min = self.getEvaluation(self.puzzle)
if min == 0:return -1
for state in next:now = self.getEvaluation(state)if now <= min:min = nowbest = state
if len(best) != 0:self.puzzle = best

关于爬山法的相关代码是用python语言实现的,其中函数self,getNeighbor 是得到八皇后相邻位置的变化信息,函数self,getEvaluation是计算八皇后位置冲突的损失。
虽然发展到今天出现了许多优秀的算法来处理各类搜索问题,但直接而又快速的爬山法不失是一种非常经典的算法。

随机重启爬山法——前进的解法

如果说爬山算法是一种经典的算法,那么随机重启爬山法可谓是爬山法2.02.02.0,它是为了克服爬山法中无法逃出局部极大值而进化得到的,最大的不同是如果当前的状态,没有达到最优值,即冲突为零的八皇后位置,就不断改变状态,重新开始搜索,直到找到不会发生冲突的八皇后位置。通过随机生成的初始状态来引导爬山法进行搜索,直到找到目标,这样找到目标的成功率会大很多。
随机重启爬山法的步骤代码:

while True:totalCosts += 1test = self.climbHill()if last == self.puzzle:if test == -1:breakelse:self.new_state()last = self.puzzleif totalCosts > 40000:return

这是随机重启爬山法的一个死循环代码片段,只有当八皇后位置信息没有冲突,即test==-1时,代码在会跳出循环,否则不断输入初始随机位置状态信息。其中当循环次数 totalCosts>4000,默认本轮搜索失败,跳出算法程序。

模拟退火法——他山之石

模拟退火法也是一种局部搜索算法,它是由KirkpatrickKirkpatrickKirkpatrick等人(1983)(1983)(1983)首次描述。退火是冶金学中的概念,它是指用于增强金属和玻璃的韧性或硬度而先把它们加热至高温再让它们逐渐冷却的过程,这样能使材料到达低能量的结晶态。模拟退火的解决方法就是开始使劲晃动(高温加热)随后慢慢降低晃动的强度(逐渐降温)。
模拟退火算法的内层循环与爬山法类似,只是它没有选择最佳移动,而是随机移动。如果该移动使情况改善,该移动则被接收。否则,算法以某个小于111的概率接收该移动。如果移动导致状态“变坏”,概率则成指数级下降——评估值ΔE\Delta EΔE变坏。这个概率也随“温度” 降低而下降:开始TTT高的时候可能允许“坏的”移动,TTT越低则越不可能发生。如果调度让TTT下降得足够慢,算法找到最优解的概率逼近于111。
模拟退火法的思路是如果移动后能够得到更优的解,那么新的解就成为当前的解,但如果移动后的解比当前解更差,则它则会以一定概率PPP成为当前的解[2]。PPP的求解公式为:
p=e−(nextCost−now)/T&ThinSpace;.p=e^{-(nextCost-now)}/T\,. p=e−(nextCost−now)/T.

其中nextCostnextCostnextCost为随机移动后状态解,nownownow为当前的状态解。这个公式这说明算法会在开始阶段更可能的接受表现较差的解,随着退火过程的不断进行,TTT 不断减小,算法越来越不可能接受较差的解,直到最后,它只会接受更优的解,随着T不断减小,nextCostnextCostnextCost 和nownownow 之间的差异也越来越重要,差异越大,被接受的概率也越低。
模拟退火法实现的步骤代码:

while True:T += 0.1next = self.getNeighbor(self.puzzle)now = self.getEvaluation(self.puzzle)if now == 0:
breakra = random.randint(0, len(next) - 1)choose = next[ra]nextCost = self.getEvaluation(choose)deltaE = nextCost - nowif nextCost == 0:self.puzzle = choosebreakif deltaE < 0:self.puzzle = choosetotalCosts += 1else:bound = math.exp(-deltaE / T)compare = random.random()
if compare >= bound:self.puzzle = choosetotalCosts += 1if T > 10000:return

函数self.getNeighborself.getNeighborself.getNeighbor 是得到八皇后相邻位置的变化信息,函数self.getEvaluationself.getEvaluationself.getEvaluation 是计算八皇后位置冲突的损失,deltaEdeltaEdeltaE 为随机得到状态的损失与当前状态的损失的差值,boundboundbound 则为概率PPP 。同样当循环次数totalCosts&gt;10000totalCosts &gt; 10000totalCosts>10000 ,默认本轮搜索失败,跳出算法程序。

A* 算法——启发式解法

A∗A*A∗算法是一个运用广泛的算法,非常适用于目标搜索,路径优化等问题。它对节点的评估结合了g(n)g(n)g(n) 和h(n)h(n)h(n) ,即到达此节点已经花费的代价和从该节点到目标节点所花费的代价:
f(n)=g(n)+h(n)f(n)=g(n)+h(n)f(n)=g(n)+h(n)
由于g(n)g(n)g(n)是从开始节点到节点n的路径代价,而h(n)h(n)h(n) 是从节点n到目标结点的最小代价路径的估计值,因此

f(n)=f(n)=f(n)= 经过结点 的最小代价解的估计代价

我们只需要考虑如何找到从该节点到目标结点所花费的代价h(n)h(n)h(n)的最小值,也就意味着达到目标代价f(n)f(n)f(n)最小。而h(n)h(n)h(n)取值也正对应启发式问题的有效性,对一个好的h(n)h(n)h(n)的评价是:h(n)h(n)h(n)是在节点n 到目标结点实际代价的下界之下,并且尽量接近真实代价。
接下来详细分析一下A∗A*A∗算法求解八皇后问题的具体步骤:
⑴、首先建立一个队列pQ和四个列表open 、openValue、close 和cloeValue ,分别装八皇后位置状态和其对于位置状态的损失值。其中队列pQ内第一列元素为位置状态损失值,第二列为位置状态信息;
⑵、取出pQ队列中第二列元素,如果该元素不在close 中,则将该行元素分别输入至列表close 和cloeValue ;
⑶、循环查询各皇后位置状态对应的损失值,如果皇后位置状态节点同时不在close 和open 列表内,则将节点对应的皇后位置状态和其损失值赋值给open和openValue,并将此节点赋值给队列pQ;如果皇后位置状态节点不在close 并且在open 内,则判断该节点对应的损失值在列表中的大小,并将最小损失值和其对应的皇后位置赋值给队列 pQ;如果皇后位置状态节点在close 内,则同样判断损失值大小,并将最小损失值和其对应的皇后位置从close 和cloeValue 列表中删除,将它们赋值给open和openValue以及队列pQ。
⑷、如果节点可扩展,将节点的扩展节点加入到open和openValue表中,将open和openValue表按照估价函数由小到大排列;否则跳转第⑵步。
A∗A*A∗算法实现的步骤代码:

while not pQ.empty():element = pQ.get()totalCosts += 1if element[1] not in close:close.append(element[1])closeValue.append(element[0])for i in self.getNeighbor(element[1]):if i not in close and i not in open:evaluate = self.getEvaluation(i)open.append(i)openValue.append(evaluate)pQ.put((evaluate, i))
elif i not in close and i in open:evaluate = self.getEvaluation(i)if evaluate < openValue[open.index(i)]:
openValue[open.index(i)] = evaluatepQ.put((evaluate, i))elif i in close:evaluate = self.getEvaluation(i)if evaluate < closeValue[close.index(i)]:
closeValue.remove(closeValue[close.index(i)])
close.remove(i)
open.append(i)
openValue.append(evaluate)
pQ.put((evaluate, i))if totalCosts > 400:return
if element[0] == 0:self.puzzle = element[1]break

以上是A∗A*A∗算法的实现过程,和它的思想一样,由到达此结点已经花费的代价和从该节点到目标结点所花费的代价组成,在选取该节点到目标结点所花费的代价时为了达到最优性,建立两个列表选取代价最小的作为估计代价。

完整代码请在我的资源处下载

参考文献

1 Sprague T B . On the Eight Queens Problem[J]. Proceedings of the Edinburgh Mathematical Society, 2009, 17:26.
2 Gruenberger F J . OPTIMIZING THE EIGHT QUEENS OVERLAY PROBLEM,[J]. Rand Corporation, 1965.
3 Ioannidis Y E , Wong E . [ACM Press the 1987 ACM SIGMOD international conference - San Francisco, California, United States (1987.05.27-1987.05.29)] Proceedings of the 1987 ACM SIGMOD international conference on Management of data, - SIGMOD "87 - Query optimization by simulated annealing[J]. 1987:9-22.
4 Bussey W H . A Note on the Problem of the Eight Queens[J]. Acta Medica Scandinavica, 1940, 103(3-5):251–258.
5 Yuen C K , Feng M D . Breadth-first search in the Eight Queens Problem[J]. ACM SIGPLAN Notices, 1994, 29(9):51-55.
6 Stuart Russell. 人工智能——一种现代方法 : 第2版[M]// 人工智能:一种现代方法.第2版. 2010.

人工智能课程设计——八皇后问题的求解算法比较相关推荐

  1. 【人工智能】八皇后问题-启发式求解

    摘要 八皇后问题是回溯算法的典型案例,在回溯法中,常常是盲目搜索,耗费过多的搜索时间.在本次实验中,使用了启发式搜索,搜索时不是任取一个分支,而是选择最佳的分支往下搜索.通过定义状态空间.操作规则.搜 ...

  2. 八皇后时间复杂度_回溯算法 | 追忆那些年曾难倒我们的八皇后问题

    文章收录在公众号:bigsai,关注更多干货和学习资源 记得点赞.在看 前言 说起八皇后问题,它是一道回溯算法类的经典问题,也可能是我们大部分人在上数据结构或者算法课上遇到过的最难的一道题-- 在这里 ...

  3. 递归设计--八皇后+神奇的口袋+数列+吃糖果

    2019.01.26 是日晴朗,纪念下放假以来第一次9点起,最近怎么越活越回去呢,别再患得患失啦,过好当下就行哟~ 本文主要是递归设计练习的总结,包含以下内容(难度依次递减) 八皇后(N皇后):全排列 ...

  4. 八皇后问题python_python求解八皇后问题

    今天突然有个行外的朋友扔了一张图给我,希望我能帮他用python做一下这个作业--八皇后问题. 八皇后问题是一种经典的数学求解问题,规则是在8×8的国际象棋棋盘上,要求在每一行(或者每一列)放置一个皇 ...

  5. python人工智能课程设计_中小学课程设计:以计算思维培养为核心的人工智能课程设计与实践...

    面对国际日趋紧张的科技竞争,发展新一代人工智能已成为各国的重要国家战略.人工智能人才的梯队建设是我国发展人工智能技术和推动产业应用的重要基础. 01存在问题 近年来教育部和各省市教育主管部门发布了一系 ...

  6. 算法分析与设计——八皇后问题(回溯法)

    在国际象棋中,皇后是最厉害的棋子,可以横走.直走,还可以斜走.棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 -- 即任意两个皇后都不能 ...

  7. 算法分析与设计-八皇后问题(回溯法)

    回溯法: 回溯的意义是在递归直到可解的最小问题后,逐步返回原问题的过程,而这里所说的回溯算法实际上是一个类似枚举的搜索尝试方法,它的主题思想是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 ...

  8. 华南理工大学计算机操作系统课程设计大作业银行家死锁避免算法模拟,2016春操作系统大作业银行家死锁避免算法模拟.doc...

    文档介绍: 2016春操作系统大作业银行家死锁避免算法模拟20160501华南理工大学"计算机操作系统"课程设计大作业计算机科学与技术专业:春2015班级:号:2015047420 ...

  9. 八皇后时间复杂度_【算法打卡】N皇后

    难度:困难 题目:     n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回 n 皇后不同的解 ...

  10. 算法:递归-八皇后问题(回溯算法)

    1.问题介绍 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯・贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不 ...

最新文章

  1. 基数排序(c/c++)
  2. 在java中如何实现声音,我如何在Java中播放声音?
  3. Altium Designer 铺地
  4. AOP切点表达式及通知类参数传递方式
  5. Metasploit--后渗透(一些基本操作方法)
  6. 起步15万年薪 这些名校高材生争当卷烟工
  7. 迅游科技上演“宫斗” 董事长总裁互相罢免
  8. 因发生下列错误 无法创建映射网络驱动器_怎么来修复“Windows无法安装所需文件的错误原因”?...
  9. 闪退没由报错_?秉承工匠精神,3步定位飞桨报错原因,你也来试试?
  10. python中的os模块几个常用的方法
  11. 高斯克吕格投影知识总结
  12. uva 11538 Chess Queen
  13. 5个典型实例告诉你:什么是数据可视化
  14. Swift学习笔记(四)
  15. 适合送女朋友的情人节礼物?畅销火热的好物分享
  16. 一个想法(续三):一份IT技术联盟创业计划书,开启众筹创业征程
  17. C++优化之使用emplace
  18. xt6使用技巧_六人花(zuo)样(si)出行指南,教你用各种姿势解锁XT6
  19. 一个列子让你弄懂SpringBoot实现后台框架的搭建
  20. 2018年美国国内高校排名

热门文章

  1. JQuery仿百度有啊人气排行特效演示
  2. 杜兰大学计算机专业,杜兰大学计算机科学
  3. SAP中的client
  4. X线、CT、B超、核磁共振区别
  5. 送送送!这本python少儿编程书籍竟然被出版社官宣了!
  6. 打印机基本故障及解决方案
  7. 30岁测试员在一家公司工作八年后,告别“体制化”终于跳槽,别再妄想靠公司养老了!
  8. 【专家访谈】疫情带来的商机风口,汽车零部件企业如何抓住机遇实现华丽转身?
  9. 达叔926词汇pdf单词提取、保存
  10. Monster: half man, half beast and very scary.