7-N皇后问题

上个例子(汉诺塔问题),我们讲解了利用递归其中一个作用,将一个问题分解成规模更小的子问题进行求解。现在用N皇后问题开说明一下递归的另一个作用:用递归代替多重循环。

1、问题描述

n皇后问题:输入整数 n,要求 n 个国际象棋的皇后,摆在 n*n 的棋盘上,互相不能攻击,输出全部方案。
输出结果里的每一行都代表种摆法。行里的第 i 个数字如果是 n,就代表第 i 行的皇后应该放在第 n 列。
皇后的行、列编号都是从1开始算。
样例输入:
4
样例输出 :
2 4 1 3
3 1 4 2

2、思路分析

有一个问题是八皇后问题,用八重循环来解决,每一行有一个皇后,用八重循环来遍历所有可能的摆放位置。 现在问题变成 N 皇后问题了,不可能用 n 重循环来解决,现在我们来用递归代替多重循环。

#include<iostream>
using namespace std;
int N;
int	QueuePos[100];		//用来存放每一行皇后的位置,最多100行
void NQueue(int k);

int main()
{
	cin >> N;
	NQueue(0);			//从第0行开始摆皇后的位置
	return 0;
}
//0~k-1行的皇后都摆好了,现在摆放第k行及其以后的皇后
void NQueue(int k)
{
	if (k == N)			//N个皇后都摆放好了
	{
		for (int i = 0; i < N; i++)
			cout << QueuePos[i] + 1 << " ";
		cout << endl;
		return;
	}
	for (int i = 0; i < N; i++)	//第k行的每个位置逐个尝试
	{
		int j;
		for (j = 0; j < k; j++)	//第k行第i列是否与前面0~k-1行的皇后冲突
		{
			if (QueuePos[j] == i || abs(QueuePos[j] - i) == abs(j - k))
				break;			//冲突,尝试下一个位置
		}
		if (j == k)				//第k行皇后与所有行的皇后都不冲突
		{
			QueuePos[k] = i;	//保存第k个皇后位置i
			NQueue(k+1);
		}		
	}
}

首先来说明一个为什么执行 NQueue(0); 就会输出所有的可能结果。原因就是在摆放第 k 行皇后的时候,我们尝试了所有的可能情况,假设 i=0,就是第 k 行的皇后摆放在第0列成立,函数继续递归,打印的这种摆放方法。函数是会返回的,i 参数加1,这时i=1,尝试摆放在第1列是否可以,如何成立,继续递归;如果与前面的皇后的摆放位置冲突了,不继续递归,i++,尝试第k行的下一个位置。所以尝试了所有的方案,会打印出所有的方案。

下面以N=4为例来说明函数的执行过程:

  • 执行 NQueue(0);
    • 放置第0个皇后,放在第0列,不冲突
  • 执行 NQueue(1);
    • 放置第1个皇后,放在第0列,冲突;放在第1列,冲突;放在第2列,不冲突
  • 执行 NQueue(2);
    • 放置第2个皇后,放在第0列,冲突;放在第1列,冲突;放在第2列,冲突;放在第3列,冲突;NQueue(2)返回
  • 执行 NQueue(1); …

最后发现第0个皇后放置在第0个位置找不到方案,返回到NQueue(0);放置第0个元素,放置在第1个位置…,如此尝试,直到找到所有的方案。

3、总结

理解递归代替多重循环的执行过程

猜你喜欢

转载自blog.csdn.net/happyjacob/article/details/87347753