题目描述(洛谷P1219)
一个如下的6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列2 4 6 1 3 5 来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1\ 2\ 3\ 4\ 5\ 6
列号 2\ 4\ 6\ 1\ 3\ 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。
解题思路
作为基础搜索题,N皇后的搜索方式可以类比运用到有关二维数组的搜索题中
其核心操作就是在递推操作的同时加入了回溯,方便于搜索的全覆盖
基本思想就是确定一个皇后的位置,然后按一定顺序确定下一个皇后位置
如果没有合适的位置则说明已确定的皇后位置无解
应迭代或回溯更换改皇后位置
基本思路
要实现二维平面内的移动,首先要明确边界的限定
1.行数 l <=n 如果最后一行l=1能够确定皇后的位置,则说明n行皇后位置全部确定(即可输出);
2.根据(1.)的描述可知,当操作到第i行时,代表前i+1行已经确定
其次要满足题中“使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子”的条件
这里事先声明第i行已确定位置的皇后在第p[i]列
在检查该条件是否成立时,选择了按行递增检查
1.据此,我们只需在检查前i-1行时,检查该行第k列是否有皇后(k==p[j]?),如果有,则证明第k列有皇后,不可再放置
2.为确定对角线是否有皇后,只需确定第i行与检查行j之差(i-j)是否等于列之差(k-p[j])即i-j==k-p[j]?
3.无需确定是否同一行,因为已知前i-1行有皇后放置
输出时,输出第i行的皇后列数p[i]
代码实现
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1000010
using namespace std;
inline int read(){
int x=0;
int f=1;
char ch;
ch=getchar();
while(ch>'9'||ch<'0'){
if(ch='-') f=-f;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n;//n*n棋盘
int cnt;//解的个数
int p[1005];//第i行皇后的列数
void print(int m){
cnt++;
if(cnt<=3){
for(int i=1;i<=m;i++){
cout<<p[i]<<' ';//输出第i行皇后的列数
}
cout<<endl;
}
return ;
}
bool find(int i,int k){//判断(i,k)位置是否合法
int j=1;
while(j<i){//检查前i-1行
if(p[j]==k||abs(j-i)==abs(p[j]-k)){//判断是否为同一列或者对角线
return 0;
}
j++;
}
return 1;
}
inline void place(int i,int k){
int h;
if(i>n){//显然前n行皇后都填过了,直接输出
print(n);
}
else{
for(h=1;h<=n;h++)
{
if(find(i,h)){//判断是否合法
p[i]=h;//如果合法,记录第i行皇后放在第h列
place(i+1,k);//寻找下一个皇后
}
}
}
}
int main(){
n=read();
place(1,n);
printf("%d",&cnt);
return 0;
}
一些话
CSP复赛快开始了,复习复习搜索是有必要的