(恩智浦杯创意组别)八皇后问题的解决思路

前言

在恩智浦杯中我们会碰到八皇后的问题,如何求解这类问题,相信网上都有很多解决方案,但是许多方法十分繁琐难以理解,同样作为一个初学者学过以后,我选出了比较容易理解的解法,帮助大家理解。

本文包括求出八皇后的92种解法和实际最短路径解决

八皇后简介

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

八皇后求解

首先这里用到的是递归的思路,额,递归我感觉就是设计出来是挺难想的,但是如果想到之后就会发现程序的结构特别简单,这里和下面的路径都会用到递归的思路。
首先我们在4 x 4 的环境下解释一下思路,这样子情况比较少,也容易理解。

橙色代表放置的皇后
首先第一行有四个位置可以放置,将四种情况加入列表,然后我们选取1,1放置,其他的 (1,2)(1,3)(1,4) 之后再讨论

放置完第一行之后没有问题,我们开始放置第二行,将第二行的四种情况加入列表,从第一个开始,放置后我们调用判断函数,发现和第一行位于同一列,不满足八皇后的条件,因此不再进入第三行的放置,而是放置(2,2),同样,(2,2)也不满足,因此我们放(2,3)
在这里插入图片描述
在(2,3)放置后,我们开始放置第三列,同样的,我们将第三列的可能情况添加进来,找找找,找不到!
如果在列表找完之后,会回退到上一列进行棋子位置重新选择!
在这里插入图片描述
也就是说,重新回到第二列的寻找皇后放置位置这一步,刚刚我们已经试过了放置第二列第三位,这次我们就试试第四位,同样的,放置后会判断是否满足八皇后条件,当然啦,这次满足。然后就从这里进入第三列的选择咯。。。。
在这里插入图片描述
第三列遍历ABCD,A不满足。B满足,进入第四层,都不满足,回退。C不满足,D不满足。
好了,第三层也遍历完了,回退!
第二层我们也发现也遍历完了,回退!
回到第一层,从(1,2)开始
之后的做法都一样啦,主要思想是遍历,可以就进阶,遍历完就回退,回退到上一层并将棋子右移一位判断,可以的话又从这里进阶。。。。。
然后这里给出一种判断成功的情况
在这里插入图片描述
在确定了第三行,正在遍历第四行的时候,判断第一个,发现不满足,然后第二个,发现满足,准备进阶下一行的时候发现已经是最后一行了,因此确定为其中一个解。记录下各个皇后的位置,然后进行第四列第三个的判断。。。后面的情况相同
这样可以遍历所有的情况,并且如果满足八皇后的解法的话会记录下来,遍历之后可以得出92种解

八皇后代码

以下是核心代码块

  void EightQueen( int row )
{
	int col;
	if( row>7 )                       //如果遍历完八行都找到放置皇后的位置则打印
	{
		Print();                       //打印八皇后的解 
		count++;
		return ;
		
	}

	for( col=0; col < 8; col++ )        //回溯,递归
	{
		if( notDanger( row, col ) )    // 判断是否危险
		{
			chess[row][col]=1;
			EightQueen(row+1);
			
			chess[row][col]=0;           //清零,以免回溯时出现脏数据
		}
	}
}

第一次进来,row=0,意思是要在第一行摆皇后,只要传进来的row参数不是8,表明还没出结果,就都不会走if里面的return,那么就进入到for循环里面,col从0开始,即第一列。此时第一行第一列肯定合乎要求(即notDanger方法肯定通过),能放下皇后,因为还没有任何其他皇后来干扰。

关键是notDanger方法通过了之后,在if里面又会调用一下自己(即递归),row加了1,表示摆第二行的皇后了。第二行的皇后在走for循环的时候,分两种情况,第一种情况:for循环没走到头时就有通过notDanger方法的了,那么这样就顺理成章地往下走再调用一下自己(即再往下递归),row再加1(即摆第三行的皇后了,以此类推)。第二种情况:for循环走到头了都没有通过notDanger方法的,说明第二行根本一个皇后都摆不了,也触发不了递归,下面的第三行等等后面的就更不用提了,此时控制第一行皇后位置的for循环col加1,即第一行的皇后往后移一格,即摆在第一行第二列的位置上,然后再往下走,重复上述逻辑。

注意,一定要添加清零的代码,它只有在皇后摆不下去的时候会执行清0的动作(避免脏数据干扰),如果皇后摆放很顺利的话从头到尾是不会走这个请0的动作的,因为已经提前走if里面的return方法结束了。

总之,这段核心代码很绕,原理一定要想通,想个十几二十遍差不多就能理解其中的原理了,递归回溯的思想也就不言而喻了。八皇后问题一共有92种情况

本文此处参考的是博客https://blog.csdn.net/qq_42552533/article/details/86684045
可在原博客中找到完整代码

八皇后路径算法

好,以上就是求解八皇后的过程,然后恩智浦杯里面是要求随机给出八皇后位置然后通过机器人移动棋子,并在最短时间内满足八皇后条件。
在这里我建议提前算出八皇后的解并导入txt文件之中,感觉读取文件会比刚刚的遍历算法快一些。
并且八皇后的解最好写成一位数组吧??64个数据的数组,因为有很多种解嘛,然后直接二维数组就可以表示所有的解了,感觉之后会比较方便
然后我把寻找路径的问题分为两个部分:
找出最合适的地图
在地图中选出最短路径

寻找最合适的地图

在参考了很多历年资料之后,发现很多参赛队伍都是认为拾取棋子和放下棋子的时候会消耗很多时间。因此如果随机摆放的位置和92种解中的重合情况最多的话,就可以减少很多的时间,因此最合适的地图都是重合度最高的地图。
通常重合度相同的都会有几个解,我们可以对这几个解都作一次路径寻找,再比较出最优的。

寻找最短路径

使用最佳地图的话很多学校都差不多,但是寻找最短路径就的方法五花八门了。
在这里介绍一下贪心算法

贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。贪心选择是采用从顶向下、以迭代的方法做出相继选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择的性质,我们必须证明每一步所作的贪心选择最终能得到问题的最优解。通常可以首先证明问题的一个整体最优解,是从贪心选择开始的,而且作了贪心选择后,原问题简化为一个规模更小的类似子问题。然后,用数学归纳法证明,通过每一步贪心选择,最终可得到问题的一个整体最优解。

还有深度优先遍历(DFS)广度优先遍历(BFS)

深度优先搜索(Depth-First-Search)是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。

广度优先搜索

广度优先搜索较之深度优先搜索之不同在于,深度优先搜索旨在不管有多少条岔路,先一条路走到底,不成功就返回上一个路口然后就选择下一条岔路,而广度优先搜索旨在面临一个路口时,把所有的岔路口都记下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路,并重复这样的操作,用图形来表示则是这样的,例子同上

有张图很形象的表现广度优先搜索
如果还有别的好的算法的话再贴上来,在这里的话我感觉贪心算法比较简单,而且唔,怎么说呢?如果优化好了之后,各种方法搜索路径感觉差别并不是太大,更多的应该在放置棋子和电机使用,移动等方面入手。
如果有机会的话再开一篇。

谢谢观赏

参考

https://blog.csdn.net/qq_43857314/article/details/88077221

https://blog.csdn.net/qq_42552533/article/details/86684045?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值