C++ / ACM 自学笔记 · v5.0

P1219 八皇后

原题入口

对应章节:五、数据结构与算法 → (十二) 搜索:递归、回溯、DFS、BFS 与记忆化。

(一) 任务与输出目标

在 n×n 棋盘上每行放一枚皇后,输出字典序前三个方案及总方案数。

(二) 建模与推导

每层处理一行,尝试列号从小到大。列冲突用 col[c],两种斜线分别由 row+c 和 row-c+n 标识。选一个位置时标记三个方向,递归下一行,返回后撤销这些标记,让下一列在同一个进入状态上继续尝试。较小列的子树先遍历,方案自然按字典序出现。

(三) 手算与过程

4×4 中第一种方案为 2,4,1,3;一条分支走不下去时逐层返回,撤销后尝试本层下一列。

按具体数据展开的处理与返回过程

(四) 带注释实现

完整源文件

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int n, position[20];
bool col[20], down[40], up[40];
int answer = 0;

void dfs(int row) {
    if (row == n + 1) {
        ++answer;
        if (answer <= 3) {
            for (int i = 1; i <= n; ++i)
                cout << position[i] << ' ';
            cout << '\n';
        }
        return;
    }
    for (int c = 1; c <= n; ++c) {
        if (col[c] || down[row + c] || up[row - c + n])
            continue;
        position[row] = c;
        col[c] = down[row + c] = up[row - c + n] = true; // 选择并保存当前行。
        dfs(row + 1);
        col[c] = down[row + c] = up[row - c + n] = false; // 返回后恢复进入本层时的占用状态。
    }
}

void solve() {
    cin >> n;
    dfs(1);
    cout << answer << '\n';
}

signed main() {
    ios::sync_with_stdio(false); // 关闭同步,使用 cin 与 cout 完成输入输出。
    cin.tie(0), cout.tie(0);

    int T = 1; // 本题读入一组数据。
    // cin >> T; // 题目给出测试组数时开启,并在 solve 中处理一组。
    while (T--)
        solve();
}

(五) 复杂度

搜索上界 \(O(n\cdot n!)\),列和递归记录占 \(O(n)\)。

返回本章题解索引 · 返回全部题号索引

查阅笔记正文与全部题解 · Ctrl / ⌘ K