递归算法:N皇后问题

问题描述:

输入一正整数n,要求n个国际象棋皇后,摆在n*n的棋盘上,互相不能攻击,即每个皇后的上下左右和对角线上仅有皇后自身。输出全部方案。

输入:

正整数N

输出:

N皇后问题的全部摆法。输出的结果里的每一行代表一种摆法。行里的第i个数字如果是n,就代表第i行的皇后应该放在第n列。皇后的行列号都是从1开始算。

样例输入:

4

样例输出:

2 4 1 3 

3 1 4 2

问题的分析及解决:

我们通常碰到的都是8皇后问题,如果说皇后数量固定的话,这个问题可以理解为是一个枚举问题。就拿8举例,我们可以写个8重循环,第一行,皇后从第一个格子开始放,然后第二行皇后从第一个格子一直放到第八个格子,判断是否符合要求,第三行以此类推,直至8个皇后摆放在棋盘上满足要求,输出摆放的情况。

但是这种代码的编写方式存在一个问题,即便是给出固定的皇后的数值,仍然要写好多层的嵌套循环。如果n的值较大,这代码撸起来让人就有点抓狂了。这个时候就要考虑如何将这么多的循环量减少,那么递归一定是将多层嵌套循环简化的一个方式。我们会发现,每一层的嵌套循环所执行的内容是相同的,那么只要一层循环就可以了,剩下的交给递归就可以搞定了。

代码思路为:定义一个函数NQueen(int k)用于递归求解,入参k从0开始,即从棋牌的第一行开始放皇后,每一列都尝试放一个,完成放置后,调用NQueen(1);然后尝试开始放第二行,第二行的皇后要和第一行的皇后位置进行对比;完成第二行的皇后放置后,调用NQueen(2);开始放置第三行皇后,第三行皇后的放置的位置需要与前2行皇后所放置的位置进行对比,完成放置后,调用NQueen(3),以此类推。如果发现皇后没有合适位置放时,且没有循环到第n个皇后,则无法继续向后调用NQueen(k)这个函数,说明递归调用终止,即该皇后的摆法是不可行的。一直递归到NQueen(N)时,输出当前QueenPos的参数值。

有些递归算法题是逆向递归的思路,假设n-1的方法已知,去求解n的情形,例如:爬楼梯算法,汉诺塔算法等。而这题是从初始值0开始,然后累加1进行递归的。这种递归的方式可以理解为正向递归。具体的实现方式如下所示。

代码

#include <iostream>
#include <cmath>
using namespace std;
int N;
int queenPos[100];//记录每一横行中,皇后所放的列位置
void NQueen(int k);

void main()
{
	cin >> N;
	NQueen(0);//从数组起始位置开始,进行递归求解
}

void NQueen(int k)
{
	if (k == N)
	{
		for (int i = 0; i < N; i++)
			cout << queenPos[i] + 1 << " ";
		cout << endl;
	}
	else
	{
		for (int i = 0; i < N; i++)//当前行遍历所有列的皇后位置是否可行,i+1位列位置
		{
			int j;
			for (j = 0; j < k; j++)//与已排列好的皇后的位置进行对比,k为已排列好的数
			{
				if (queenPos[j] == i || abs(queenPos[j] - i) == abs(k - j))
					break;//如果当前皇后所放置的位置与已知皇后的位置发生冲突,则跳出循环
			}
			if (j == k)
			{
				queenPos[k] = i;
				NQueen(k + 1);//正向递归求解k+1
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值