洛谷:P1219:八皇后 Checker Challenge


洛谷:P1219:八皇后 Checker Challenge

题目

P1219:八皇后 Checker Challenge

分析

用八皇后问题开始DFS的学习,可以算是个惯例。

DFS标准框架

flowchart TD A[进入DFS,代入“进程”参数] --> C{是否已经全部完成} C -->|是| D[输出、统计等工作,并返回] D --> J[后续程序代码] C -->|否| E{{循环:遍历可选位置}} E --> F{放置是否合法} F -->|否| E F -->|是| G[放置、标记] G --> H[递归调用下一个DFS] H --> I[撤销标记,恢复现场] I --> E

实际编程中,因为题目的不同,这个框架会有变化。其中最重大的变化无非两处:

  1. 下一个DFS可以分支进行,比如加不加当前选项构成两个DFS分支。
  2. 回溯有时是不需要的。
是否已经全部完成

对于八皇后问题,如果放置了8个皇后,那么已经全部完成。

遍历可选位置

我们每行放一个皇后,因此对于某一行来说,只有8个列的位置可以选择。

放置是否合法

需要检查列、两条斜线的冲突。

放置

如果可以放,那么需要进行相应的标记:该列有了一个皇后。不需要进行斜线设定,因为可以根据行列判断。

下一个DFS

本行放置完毕,进入下一行的放置:dfs(current_row + 1)

撤销和恢复

某一行皇后的放置会影响后续行的放置,所以返回时需要撤销。

在本题中,上述三个操作的代码是:

    ans[row] = i;
    dfs(row + 1);
    ans[row] = 0;

其中,ans[row] = i表示row这一行的皇后放在了i列。= 0就是清除工作(列从1开始)。

合法放置的判定

我们用一个辅助函数来判定放置是否合法。

bool check(int row, int col)
{
    for (int i = 1; i < row; i++)
    {
        if (ans[i] == col ||                    // 同列
            abs(row - i) == abs(col - ans[i]))  // 对角线
            return false;
    }
    return true;
}

对于某个格子(位于(row, col)),我们检查之前的行(1row-1):

  1. 如果某一行该列已经有皇后(ans[i] == col);
  2. 或者对角线上有皇后,那么就是不合法的位置。
  3. 否则,就是合法的位置。

注意,只有check返回true,才可以进行后续的“标记 - 下一步 - 撤销”工作。

答案

Solution

思考

Previous Next