八皇后dfs全排列——洛谷1219
[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*N的棋盘最多只能摆下N个皇后,接下来就是找到所有合法的皇后排列,这是两个问题,合法,排列,先解决合法,摆下一个皇后之后如何才能知道这个位置是否合法,最简单的方法就是逐一检索前面摆下皇后的位置,判断前面摆下的皇后中有没有与该皇后在同一列或者同一对角线的皇后(不用判断是否在同一行,因为我们在编码的时候就是逐行放皇后的),是否在同一行=列只需要判断一下,两皇后位置的纵坐标是否相同即可,是否在同一对角线,很简单,在函数中满足y=x+b的都是在同一对角线的(x,y)的特点是他们坐标相减是同一个数,即斜率为1,公式(x1,y1),(x2,y2)有|x1-x2|=|y1-y2|,接下来就是求这几个皇后的全排列问题,我们在解决全排列问题的时候通常会使用dfs算法
看代码:
#include<iostream>
using namespace std;
int n, sum, a[110];
int awa(int h, int l) {
//h:行
//l:列
int i;
for (i = 1; i <= h - 1; i++)
//遍历前面每一行,也就是遍历前面已经摆好的皇后的编号
if ((l == a[i]) || (abs(h - i) == abs(l - a[i])))return 0;//判断是否在同一列或同一对角线
return 1;
}
void queen(int qwq) {
int i;
if (qwq > n) {
sum++;
if (sum <= 3) {//前三组输出
for (i = 1; i <= n; i++)cout << a[i] << " ";
cout << endl;
return;
}
else return;
}
for (i = 1; i <= n; i++) {
//我们用qwq也就是每个皇后的编号代表他们所在行的编号,逐个遍历每一列i
if (awa(qwq, i) == 1) {//当前皇后和前面的皇后不会互相攻击
a[qwq] = i;/*摆下当前皇后*/
queen(qwq + 1);/*继续来到下一列放置皇后*/
//记得要回溯,这是dfs求全排列方法
a[qwq] = 0;/*回溯*/
}
}
}
int main() {
cin >> n;
queen(1);
cout << sum << endl;
return 0;
}