问题描述:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。
输入:
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
输出:
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
【思路】:数据量很小可直接暴力回溯即可,优化的话可以开个vis数组来标记一下之前放的皇后。直接从n*n的棋盘的第一行开始向下方即可,以下代码从0开始所以我写的是从第0行开始搜。先说一下回溯的条件,也就是结束“叶子节点”(我把最深层的那行称为叶子节点)递归的条件,也就是当k(你当前的行数)能搜到第n行时也就是一个超出棋盘的下一行时便可以进行回溯。
然后如果不满足结束条件,则自己假设将皇后放在改行的每列上看看放在哪几个列上可行。这里注意不满足的条件,因为每行只可能放一个皇后所以只需要判断,是否在一列,左斜线,右斜线即可。切记,左斜线时不可求绝对值,直接两个坐标相减判相等即可。如若加绝对值,则对角线右上方的和左下方的情况会混。所以直接利用坐标特点判断即可,不明白的可以直接自己画一个空白坐标系,看一看在同一斜线上的点的纵坐标和横坐标的关系,不难看出。
以下给出代码。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
using namespace std;
#define LL long long
const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const int M = 1e9 + 7;
int a[20];
int cnt,n;//n为n个皇后 棋盘大小为n*n cnt代表多少种放置方法
void f(int k)//一行一行的递归 然后进行回溯
{
if(k>=n){
//只要把棋盘都放完即可 即结束递归的条件就是传入的值比棋盘行数大一 我这从0开始所以等于n就可
cnt++;
return ;
}
else
{
for(int i=0;i<n;i++){
bool flag = false;
a[k] = i;//在第k行i列上
for(int j=0;j < k;j++){//看是否出现皇后的冲突 和已经放上的判断 就判断那三个条件
//不可求绝对值 不然在对角线右上方和左下方的情况会判断错误 刚刚脑子一懵添了个绝对值
if(a[j]==a[k]||(j-a[j])==(k-a[k])||(a[k]+k)==(a[j]+j))//判断是否在一列 左斜 右斜
{
flag = true;
break;
}
/*if((a[j]==a[k])||(abs(k-j)==abs(a[j]-a[k]))){//如果这样的话是可以加绝对值来表示两点共线的 y2-y1/(x2-x1)=+1/-1;
flag = true;
break;
}*/
}
if(flag==false)
{
f(k+1);
}
}
}
}
int main(){
while(cin>>n){
if(n==0)
break;
cnt = 0;
f(0);//从第0行开始递归 先在棋盘第一行放入一个皇后
cout<<cnt<<endl;
}
return 0;
}