八皇后问题

一、什么是八皇后问题?

八皇后问题是一个古老的问题,于1848年由一位国际象棋棋手提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,如何求解?

二、如何求解?

以高斯为代表的许多数学家先后研究过这个问题。后来,当计算机问世,通过计算机程序的运算可以轻松解出这个问题。

所谓递归回溯,本质上是一种枚举法。这种方法从棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果摆放成功,则继续递归一层,摆放第三个皇后…

如果某一层看遍了所有格子,都无法成功摆放,则回溯到上一个皇后,让上一个皇后右移一格,再进行递归。如果八个皇后都摆放完毕且符合规则,那么就得到了其中一种正确的解法。

说起来有些抽象,我们来看一看递归回溯的详细过程。

代码如下:

#include <iostream>
#include<math.h>
#include<typeinfo>
#include"delegate.h"
using namespace std;

#define  chessBoardSize  8
class Queen8
{
public:
	int(*chessBoard)[chessBoardSize];//int[8]类型的指针,
public:
	Queen8() 
	{
		 chessBoard = new int[chessBoardSize][chessBoardSize];
		 memset(chessBoard,0,sizeof(int)*chessBoardSize*chessBoardSize);
	}
	//在第几行落子,因为一行肯定只有一个,x默认值为0
	bool settleQueue(int x =0)
	{
		//放下了8个棋子才返回
		if (x == chessBoardSize)
			return true;

		//遍历当前行的所有列
		for (int y = 0;y<chessBoardSize;++y)
		{
			//清空这一行的数据以免干扰,因为走到头失败的话倒回来,之前的位置也会设置为1
			for (int i = 0; i < chessBoardSize; ++i)
			{
				chessBoard[x][i] = 0;
			}
			if (checkBoard(x,y))
			{
				chessBoard[x][y] = 1;
				if (settleQueue(x+1))
				{
						return true;
				}
			}
		}
		return false;
	}
	//检查落子符合要求
	bool checkBoard(int x,int y)
	{
		int i = 0;
		//检查纵向
		while (x-1-i>=0)
		{
			if (chessBoard[x - 1 - i][y] == 1)
				return false;
			++i;
		}
		//检查左斜上方块
		i = 0;
		while (x-1-i>=0&&y-1-i>=0)
		{
			if (chessBoard[x - 1 - i][y-1-i] == 1)
				return false;
			++i;
		}
		//检查右斜上方
		i = 0;
		while (x - 1 - i >= 0 && y + 1 + i < chessBoardSize)
		{
			if (chessBoard[x - 1 - i][y + 1 + i] == 1)
				return false;
			++i;
		}
		return true;
	}
};


int main()
{
	Queen8 q;
	q.settleQueue();
	for (int x =0;x<8;++x)
	{
		for (int y =0;y<8;++y)
		{
			cout << q.chessBoard[x][y] <<" ";
		}
		cout << endl;
	}
	system("pause");
	return 0;
	
}

上述代码的核心处在于settleQueue函数;

这个函数是在第几行落子,一直在循环中递归这个函数,放下8个棋子后会直接返回。

循环递归的原理如下

调用settleQueue------>第0行第0列------>清空这一行的数据------>检查这个位置------>可以放

------>继续调用settleQueue------>第1行第0列------>清空这一行数据------>检查这个位置------>不能放

------>for循环到第1行第1列------>清空这一行数据------>检查位置------>不能放------>继续for循环

…一直这样

(讲一个特殊情况)

------>放到了最后一行,最后一列,没有放慢8个棋子------>settleQueue返回false

------>返回上一行的settleQueue------>上一行的因为已经放下过一次棋子,所以清空一行的数据就很有必要------>然后for循环,棋子右移一个------>检查这个位置

------>继续调用settleQueue走到下一行

三、总结一下

就是循环递归每一行的每一列的位置。直至放下8个棋子返回true。

如果一行循环完了,棋子没有放下8个,就会返回false,递归倒回上一行进行for循环遍历

四、代码运行结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值