所谓一山不能容二虎,在 n×n 的棋盘上放置彼此不受攻击的 n 个皇后。按照国际象棋的规则,皇后可以攻击与
之在同一行、同一列、同一斜线上的棋子。设计算法在 n×n 的棋盘上放置 n 个皇后,使其彼此不受攻击。
输入:
4
输出:
2 4 1 3
3 1 4 2
可行方案数:2
问题分析:
题目要求不同行不同列不同斜线上,因为约束条件太多和考虑复杂度,我们不可能直接每个都枚举,可以先以行为主导,每行只放一个,找到可行的位置后就进行下一行的搜索,当某个位置放第t个皇后时,需要判断与前面已经放好的t-1个皇后的列和对角线时候相同,都不相同就可以在该位置放t皇后,判断是否在同一对角线可以用两位置行的差的绝对值和列的差的绝对值是否相等,可以以深度优先搜索的方式进行搜索,在t行的第i列判断时候可以放,可以放就向深一行进行搜索,不可以放就继续判断i+1,因为是n行n列的棋盘有n个皇后,说明每一行每一列都已经有一个且只有一个皇后,如果在第t行全部搜素都没有可行的位置说明下面几行继续放也没意义,这时就需要回溯,返回上一行继续搜索,直到n个皇后放完,当一种方案确定后也需要回溯继续搜索时候还有另外放方案。
代码:
#include<iostream>
#include<math.h>
using namespace std;
#define M 105
int n;//皇后
int x[M];//第M个皇后放在M行X[M]列
int num;//可行方案的个数
bool place(int t)
{//判断第t个皇后是否能放在第i列
bool ok = true;
for (int i = 1; i < t; i++)//判断i列是否与前t-1个皇后的位置冲突
{
if (x[i] == x[t] || (t - i) == fabs(x[t] - x[i]))//因为已经是以行为主导,所以判断是只需要判断列和对角线
{
ok = false;
break;
}
}
return ok;
}
void Backtrack(int t)
{
if (t > n)//如果当前位置为n,则说明已经得到一个方案
{
num++;
for (int i = 1; i <= n; i++)//打印路径
cout << x[i] << " ";
cout << endl;
}
else
for (int i = 1; i <= n; i++)
{
x[t] = i;//第t行第x[t]列,也是此时的第i列
if (place(t))
Backtrack(t + 1);//如果不冲突。则进行下一行的搜索
}
}
int main()
{
cin >> n;
num = 0;
Backtrack(1);
cout << "可行方案数:" << num << endl;
return 0;
}