问题描述
题目
输入一个正整数N,请写一个程序,输出N皇后问题的全部摆法。
输入
输入皇后的个数n(n<=13)
样例
4
输出
输出长度为n的正整数。
输出结果里的每一行都代表一种摆法。
行里的第i个数字如果是n,就代表第i行的皇后应该放在第n列。
皇后的行、列编号都是从1开始算
样例
2413 3142
思路
我们优先考虑在每一列放皇后,所有皇后不能有出现在同一行的,所以我们用used数组存储每个皇后所在的行,放过的行不能再放。最后再写一个check函数对皇后对角线上的位置进行检查,如果对角线上也没有皇后,则说明目前这种摆法是可以的,迭代开始摆下一行,摆完所有行就是一种正确的摆法。最后利用回溯输出所有可能的摆法。
代码实现
我们先来看用以回溯的函数batrack。
void batrack(vector<int>& path,vector<int>&used,int n){//path用来存储本次放置皇后的位置,used用来存储这一行是否放置过皇后,n是棋盘大小
if(path.size()==n){//如果放置的皇后数量等于棋盘长度,说明找到了一种解法,输出这种解法
for(int i=0;i<n;i++){
cout<<path[i];
}
cout<<endl;
}
for(int j=0;j<n;j++){//遍历每一行,放置皇后
if(used[j]==1)//如果这一行已经放置过皇后了,则跳过这一行
continue;
path.push_back(j+1);//否则把皇后放在这一行
if(!check(path)){//检查皇后对角线上是否有皇后存在
path.pop_back();//如果有,则不能放在这一行
continue;
}
used[j]=1;//否则可以放在这一行,在used数组中把这一行标记为已放置皇后
batrack(path,used,n);//递归,讨论下一列皇后放置的位置
used[j]=0;//回溯,把皇后拿走,考虑下一种摆法
path.pop_back();//拿走皇后
}
}
接下来看check函数的实现
bool check(vector<int>& path){
int len=path.size();
for(int i=len-2;i>=0;i--){//从棋盘最后摆的那列的前一列开始检查
if(path[len-1]-path[i]==len-1-i||path[i]-path[len-1]==len-1-i){
//如果行差的绝对值等于列差,则说明两个皇后在对角线上,不可以这样摆,返回false
return false;
}
}
//没有找到,说明可以这样摆,返回true
return true;
}
再在主函数中实现输入输出的功能即可。
int main(){
int n;
cin>>n;
vector<int> path;
vector<int> used(n,0);
batrack(path,used,n);
}