八皇后问题

八皇后问题(回溯)

1.问题描述

在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

2.问题分析

历史

这是个老经典的问题了,在1848年由国际西洋棋棋手马克斯·贝瑟尔提出,是回溯算法的典型案例。

尔后陆续有不同的学者提出自己的见解。 大数学家高斯认为一共有76种摆法,1854年在柏林的象棋杂志上不同的作者发表了多达40种不同的见解,后来还有人利用图论的方法得出共有92种摆法。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。

而现在,学习了高级语言还有算法的我们可以轻轻松松 😄 搞定这个问题。


暴搜

我觉着第一次接触这个问题的人首先想到的就是暴搜,穷尽所有情况的话大概就是64个空里面选8个,口算一下就是4426165368,大概也就是44亿😦,不过让程序多跑一跑也不是不行。假如再做一些简单的剪枝的话也可以稍微降低一点复杂度,但是大多属于是把44亿变到40亿变到10亿这种。小了,但是没有完全小😆。那么有没有办法一刀砍狠一点呢?那就得请出我们的回溯算法了。

仔细思索一下暴搜计算量如此之大原因,你会发现存在大量重复性计算

如上图所示,很明显摆到这一步已经不符合规则了,但是暴搜算法依旧会继续遍历完包含这个组合的所有可能摆法,盲目地按既定顺序枚举所有的可能方案,而非哪里有冲突就调整哪里,这样就导致了其效率非常之低😱。


回溯算法

但是回溯算法就不一样了,它的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试,直到无路可走

详细一点的话,回溯算法解决问题的一般步骤:

1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。

2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。

3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

在确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止😟。

八皇后问题就是回溯算法的一个典例😃,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。

其实,回溯算法说白了也是暴搜(穷举法)。不过回溯算法使用剪枝函数,剪去一些不可能到达 最终状态(即答案状态)的节点,从而减少状态空间树节点的生成,也就大大减少了计算量和时间消耗。

讲了这么多,情况就是这样,懂得都懂,不懂的我也不多说,上代码😏。


3.完整代码

using System;//使其包含Console等类
public class eight_queen//创建一个包含所需函数的类
{

	int N = 0;//计数
	int[] queen = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };//开辟数组用于存放每一行皇后的位置

	public bool judge(int n, int t)//判断第n行的皇后是否违规
	{
		for (int i = 1; i < n; i++)
			if (queen[i] == t || queen[i] - t == i - n || queen[i] - t == n - i) return false;
			//判断依据分别为是否同一列,是否处于主副对角线上
		return true;
	}

	public void print()//输出结果 +代表皇后
	{
		Console.Write("Answer:");
		Console.WriteLine("{0,2:d}",N);

		for (int i = 0; i < 8; i++)
		{
			for (int j = 0; j < queen[i]; j++)
				Console.Write(".");
			Console.Write("+");
			for (int k = queen[i]; k < 8; k++)
				Console.Write(".");
			Console.WriteLine();
		}
	}

	public void put_queen(int n)//深搜摆放皇后
	{
		for (int i = 1; i < 9; i++)//尝试每一行的八种可能摆法
		{
			if (judge(n, i))//如果该位置可行
			{
				queen[n] = i;//先存起来
				if (n == 8)//若true此时已经产生了一种可行的摆法
				{
					N++;
					print();
					return;//触底反弹
				}
				put_queen(n + 1);//假如还没摆到第八行就继续摆下一行
			}
		}
		queen[ n-1 ] = -1;//此时无可行结果,恢复现场并且回溯
		return;
	}

}
public class Program
{
	static void Main(string[] args)//一个C#控制台程序必须包含一个Main方法,且必须为静态而非公共方法
	{
	    eight_queen S = new s();
		S.put_queen(1);//调用深搜函数,从第一行开始search
	    Console.WriteLine();
	    Console.WriteLine("The end, thanks.");
	}
}

(图片来自网络,侵删)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值