P1219 [USACO1.5] 八皇后 Checker Challenge 题解

题目链接 https://www.luogu.com.cn/problem/P1219

[USACO1.5] 八皇后 Checker Challenge

题目描述

一个如下的 \(6 \times 6\) 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 \(2\ 4\ 6\ 1\ 3\ 5\) 来描述,第 \(i\) 个数字表示在第 \(i\) 行的相应位置有一个棋子,如下:

行号 \(1\ 2\ 3\ 4\ 5\ 6\)

列号 \(2\ 4\ 6\ 1\ 3\ 5\)

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 \(3\) 个解。最后一行是解的总个数。

输入格式

一行一个正整数 \(n\),表示棋盘是 \(n \times n\) 大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

样例 #1

样例输入 #1

6

样例输出 #1

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

提示

【数据范围】
对于 \(100\%\) 的数据,\(6 \le n \le 13\)

题目翻译来自NOCOW。

USACO Training Section 1.5

思路描述

题意就是在\(n \times n\)的棋盘上每行、每列,每条对角线和两条主对角线的所有平行线,最多只有一个皇后。\(n\)的范围是\(6 \le n \le 13\),我们可以直接用\(DFS\)来搜索,用bool类型的数组来标记是否被占就行了,那这道题就是一道简单的深搜题。

\(dfs\)代码:

void dfs(int x) { //考虑第i行的皇后在哪一列。
	if(x==n+1) { //终止条件就是超过棋盘的范围
		ans++;
		if(ans<=3) { //如果方案数超过3
			for(int i=1; i<=n; i++)
				cout<<a[i]<<' ';//输出前3个方案
			cout<<endl;
		}
		return;
	}
	for(int i=1; i<=n; i++) {
		if(b[i]==false&&c[x+i]==false&&d[x-i+n]==false) { //分别判断列,右上到左下对角线,左上到右下对角线是否有棋子
			a[x]=i;//记录纵坐标
			b[i]=true;//列被占
			c[x+i]=true;//右上到左下对角线被占
			d[x-i+n]=true;//左上到右下对角线被占
			dfs(x+1);
			b[i]=false;//将三个数组全部清空
			c[x+i]=false;
			d[x-i+n]=false;
		}
	}
}

主函数代码:

int main() {
	cin>>n;
	dfs(1);
	cout<<ans<<endl;
	return 0;
}//挺简单的就不用解释了

完整代码:

#include<iostream>
#include<cstring>
using namespace std;
int n;
int a[100];
bool b[100],c[100],d[100];
int ans;
void dfs(int x) {
	if(x==n+1) {
		ans++;
		if(ans<=3) {
			for(int i=1; i<=n; i++)
				cout<<a[i]<<' ';
			cout<<endl;
		}
		return;
	}
	for(int i=1; i<=n; i++) {
		if(b[i]==false&&c[x+i]==false&&d[x-i+n]==false) {
			a[x]=i;
			b[i]=true;
			c[x+i]=true;
			d[x-i+n]=true;
			dfs(x+1);
			b[i]=false;
			c[x+i]=false;
			d[x-i+n]=false;
		}
	}
}
int main() {
	cin>>n;
	dfs(1);
	cout<<ans<<endl;
	return 0;
}

时间复杂度

因为n最大只有13所以不用担心时间复杂度;

END:如有不足,欢迎指出

posted @ 2023-07-19 19:44  zzrlmt  阅读(33)  评论(0)    收藏  举报