n皇后问题

131 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

7-16 n皇后 (10 分)

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将n个皇后放在棋盘上(有n× n个方格),使它们谁也不能被吃掉!这就是著名的n皇后问题。对于某个满足要求的n皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...bn,其中bi为相应摆法中第i行皇后所处的列数.

输入格式: 一个整数n,表示棋盘大小。

输出格式: 输出所有满足要求的解,每行一个答案。最后输出一个数,表示一共有多少个解。

输入样例: 4

输出样例:

2 4 1 3

3 1 4 2

2

思路: 其实不管是什么题目 首先要做的事情就是思考一下这是什么类型的题目 需要我用什么方法来实现 我们先来看下题目 题目要求到每个皇后不能在同一行或同一列上 那么很简单 这不就是个全排列嘛 我们暴力一点 把全排列全输出出来 一个个检索过去看是否合法不就行了嘛 但是要知道 全排列是个阶乘 n越大消耗的时间就越大 这不符合我们简单快速的理念 想到这里了 我们不妨在思考一下 我们只要在全排列的过程中把不符合的直接删掉不就省下来好多时间了嘛 那么什么方法能做到呢 那就得靠递归回溯了

关于递归回溯我在全排列中已经十分详细的介绍过了 我们只要针对其中判断合法性的部分稍作修改即可

下面我们来讲一下这道题目的judge函数要如何来写 judge函数是在递归回溯中必不可少的函数 需要我们结合题意来写 这道题目的意思是 每个皇后不能在同一行 同一列 同一条主对角线 同一条副对角线 那么我们就一个一个的来进行分析

  • 同一行:递归回溯是一层一层的从上往下搜索的 所以 这就直接避免了同一行的现象
  • 同一列:递归回溯每一层的值都被保存在x[t]中 只要保证没有两个相同值的x[t]即可
  • 同一主对角线:通过找规律我们可以发现 主对角线上的任意一点x-y值恒定
  • 同一副对角线:通过找规律我们可以发现 副对角线上的任意一点x+y值恒定
  • 把主对角线与副对角线的判定式结合起来一起看 我们会发现 其实只要保证两个点的横坐标差的绝对值与纵坐标差的绝对值相等 即可保证在同意对角线上了

搞清楚这些后 我们来修改judge函数

bool judge(int t)

bool judge(int t){
	int i;
	for (i=1;i<t;i++){
		if(x[i]==x[t]||abs(i-t)==abs(x[i]-x[t])){
			return false;
		}
	}
	return true;
}

n皇后题目完整代码如下

#include <bits/stdc++.h>
using namespace std;
int x[100],n,cnt;
bool judge(int t){
	int i;
	for (i=1;i<t;i++){
		if(x[i]==x[t]||abs(i-t)==abs(x[i]-x[t])){
			return false;
		}
	}
	return true;
}
int Output (int t){
	for (int i=1;i<=n;i++){
		cout<<x[i]<<" ";
	}
	cout<<endl;
	cnt++;
	return 0;
}
void Backtrack(int t){
    int i;
	if(t>n){
		Output(t); 
	}
	else {
		for (i=1;i<=n;i++){
			x[t]=i;
			if(judge(t)){
				Backtrack(t+1);
			}
		}
	}
}
int main(){
	cin>>n;
	Backtrack(1);
	cout<<cnt;
	return 0;
}