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

题解

通过题意我们可以知道任意两个皇后 不可以在同一行 同一列 同一斜线 因此 我们可以采用深度优先搜索搜索出所有的可能性

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1005;
int ans[N], x[N], y[N] ,z[N];//
int sum;//记录已经输出了多少行结果 题意要求三行结果
int n;//n个皇后
void dfs(int r) {
    //如果当递归深度已经大于所求的皇后的数量
    if (r>n) {
        if (sum<3) {//题目要求输出前三种
            for (int i=1; i<=n; i++) {
                cout << ans[i]<< " ";
            }
            cout << endl;
        }
        sum++;
        return;
    }
    for (int i=1; i<=n; i++) {
        if (x[i]==0 && y[i+r]==0 && z[r-i+n]==0) {//如果当前状态下 行 列 斜 都没有皇后占用
            //占用当前位置 并标记所在的行列斜
            ans[r]=i;
            x[i]=1;
            y[i+r]=1;
            z[r-i+n]=1;
            //继续搜
            dfs(r+1);
            //回溯
            ans[r]=0;
            x[i]=0;
            y[i+r]=0;
            z[r-i+n]=0;
        }
    }
}
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0), std::cout.tie(0);
    cin >> n;
    dfs(1);
    cout << sum << endl;
    return 0;
}