HDU-2553 N皇后问题 经典深搜DFS+数学分析

话不多说先上题目

Problem Description

在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。

Input

共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。

Output

共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。

Sample Input

1
8
5
0

Sample Output

1
92
10

对于n皇后问题,个人看来应该说是非常经典的深搜问题了,还需要加上一些数学分析使其过程更加简单。
题意大概就是n*n个棋盘里放n个皇后,这n个皇后不能在同一行同一列或是同一斜线上,问你一共有多少种放法。讲方法之前必须先说明一点就是我们在最终计算出数量后需要将其打表储存,就是我们通过下列方法计算出N<=10的全部情况,打表,之后直接访问表中数据即可,否则会导致超时
下面开始讲方法,先建立一个标记二维数组记为a[3][100],之所以行只需要三个空间是因为我们每次都只需要对列、右对角线以及左对角线进行标记,而对于同一行不能放置我们将行作为递归的元素即可,相当于每次都在一行里找出一个可行位置然后进入下一行,每放置一个棋子我们便将其对应的三个方向的所有元素都标记为1.
那么对于如何进行标记,思考如下:

  1. 同一列的元素我们直接a[1][i]=1,表示每行的第i个位置不能放皇后;
  2. 左对角线元素则令a[2][row+i]=1,row表示行,i表示列,对于左对角线其共同点为行加列为一个定值故我们将这个定值进行标记
  3. 右对角线元素的特点为row-i为一个定值,但是考虑到数组下标不能为负统一加上n即可,即a[0][row-i+n]=1;

这里联想一下函数就很具体

因此我们可以得到递归主体

	for (i = 1; i <= n; i++)
	{
		if (a[0][row - i + n] == 0 && a[1][i] == 0 && a[2][row + i] == 0)
		{
			a[0][row - i + n] = a[1][i] = a[2][row + i] = 1;
			lu(row + 1);
			a[0][row - i + n] = a[1][i] = a[2][row + i] = 0;
		}
	}

以及判停条件

if (row == n + 1)
	{
		sum++;
		return;
	}

通过这种方法写出的代码非常简单
AC代码如下:

#include
#include
#include
using namespace std;
int a[3][100], b[15]; 
int n, sum;
void  lu(int row)//row代表了行
{
	int i;
	if (row == n + 1)
	{
		sum++;
		return;
	}
	for (i = 1; i <= n; i++)//i代表列
	{
		if (a[0][row - i + n] == 0 && a[1][i] == 0 && a[2][row + i] == 0)
		{
			a[0][row - i + n] = a[1][i] = a[2][row + i] = 1;
			lu(row + 1);
			a[0][row - i + n] = a[1][i] = a[2][row + i] = 0;
		}
	}
	return;
}
int main()
{
	for (n = 1; n <= 10; n++)//方便理解我省略了数组的第一个元素从下标1开始
	{
		int s;
		s = sizeof(a);
		memset(a, 0, s);
		sum = 0;
		lu(1);
		b[n] = sum;//b[n]存储打表的数据
	}
	while (scanf("%d", &n), n)
	{
		printf("%d\n", b[n]);
	}
	return 0;
}

你可能感兴趣的:(笔记)