题目
分析
用八皇后问题开始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
实际编程中,因为题目的不同,这个框架会有变化。其中最重大的变化无非两处:
- 下一个DFS可以分支进行,比如加不加当前选项构成两个DFS分支。
- 回溯有时是不需要的。
是否已经全部完成
对于八皇后问题,如果放置了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)),我们检查之前的行(1到row-1):
- 如果某一行该列已经有皇后(ans[i] == col);
- 或者对角线上有皇后,那么就是不合法的位置。
- 否则,就是合法的位置。
注意,只有check返回true,才可以进行后续的“标记 - 下一步 - 撤销”工作。
答案

