回溯法过程
在试探过程中,皇后的放置需要检查她的位置是否和已经放置好的皇后发生冲突,因此需要一个检查函数
假如两个皇后被放置在(i,j)和(k,l)上 ,当且仅当 |i-k|==|j-l| 时两个皇后在同一条对角线上。
(1).先从首位开始检查,如果不能放置,则检查该行的第二个位置,依次进行下去,直到找到一个可以放置皇后的位置,保存当前状态,然后转下一行重复该操作。
(2).如果检查该行所有位置均不能放置,说明上一行放置的皇后无法让所有的皇后找到自己合适的位置。因此就要回溯到上一行,继续检查该皇后后面的位置。
附代码
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int ans = 0,queen[15];
int n,num[15];
int check(int x) //用于检查皇后是否可以放在此位置
{
for(int i = 0;i<x;i++)
{
//queen[i] == queen[x] 用于保证元素不在同一列
//abs(queen[i] == queen[x] == abs(n-i)) 用于约束元素不在同一行且不在同一条斜线上
if(queen[i] == queen[x] || abs(queen[i] - queen[x]) == abs(x-i))
return 0;
}
return 1;
}
//核心函数 回溯法思想
void NQUEEN(int x) //回溯尝试皇后的位置
{
for(int i = 0;i<n;i++)
{
//首先将皇后放置在第0列的位置
queen[x] = i; //姜皇后摆在当前循环到的位置
if(check(x))
{
if(x == n-1)
ans++; // 如果全都摆好,则ans++
else
NQUEEN(x+1); // 否则继续摆下一个皇后
}
}
}
void init() //一定要打表,不然会超时
{
for(n = 1;n<=10;n++)
{
ans = 0;
NQUEEN(0); //从横坐标0开始尝试
num[n] = ans;
}
}
int main()
{
init();
while(scanf("%d",&n))
{
if(n == 0)
break;
printf("%d\n",num[n]);
}
}