1.题目描述
有一个n×n 的国际象棋棋盘(n 行,n 列的方格图),请在棋盘中摆放 n 个受伤的国际象棋皇后,要求:
- 任何两个皇后不在同一行。
- 任何两个皇后不在同一列。
- 如果两个皇后在同一条 45 度角的斜线上,这两个皇后之间行号的差值至少为 3 。
请问一共有多少种摆放方案。
2.输入格式
输入的第一行包含一个整数 n。
3.输出格式
输出一个整数,表示答案。、
4.样例输入
4
5.样例输出
2
6、数据范围
1≤n≤10.
7.原题链接
8.解题思路
本题有三个限制:行、列、对角线行的距离至少为3。行比较好办,我们枚举每一行是否应该放皇后,每一行判断该放哪个位置,自然就能够跳过对行的判断。列,我们直接判断是否在同一列即可。而难点在对角线上。我们可以利用初中学过的y=kx+b和y=-kx+b,因为斜率都是1,所以k默认为1,不用管。对于处在对角线的皇后,解出b看是否相等,同时行的距离是否大于3即可判断。
同时用 a数组来存每一行对应的列,就可以避免开二维数组得以省下空间。
1、正对角线:b=y-x
2、反对角线:b=y+x
check函数每次判断两组坐标,i和a[i], r和c,题目中有注释就不多说了。
#include <iostream>
using namespace std;
const int N = 20;
int n;
int a[N];//用来存每一行对应的列。比如a[u] = i就是第u行第i列(不考虑下标从0开始,只是举例说明)
int res;
bool check(int r, int c)
{
for (int i = 0; i < r; i ++ )//枚举每一行,a[i]就是每一列
{
//列不能有相同
if (a[i] == c) return false;
//正对角线
if (a[i] - i == c - r && (abs(r - i) < 3)) return false;
//反对角线
if (a[i] + i == c + r && (abs(r - i) < 3)) return false;
}
return true;
}
void dfs(int u)
{
if (u == n)
{
res ++ ;
return;
}
for (int i = 0; i < n; i ++ ) //u是行,i是列
if (check(u, i))
{
a[u] = i;
dfs(u + 1);
a[u] = 0;
}
}
int main()
{
cin >> n;
dfs(0);
cout << res << endl;
return 0;
}