1. 双皇后问题:棋盘上的排列组合挑战
1.1 问题本质与约束条件
想象一下国际象棋棋盘上的皇后,它们可以沿着行、列和两个对角线方向无限延伸攻击。现在我们要在这个棋盘上放置两种颜色的皇后(黑皇后和白皇后),每种颜色各n个,且需要满足以下条件:
- 同一颜色的皇后不能互相攻击(即不能同行、同列或同对角线)
- 不同颜色的皇后可以放在同一格(但题目中这种情况不会发生)
- 棋盘上有些位置是禁区,不能放置任何皇后
这个问题的难点在于两种颜色的皇后放置会相互影响——黑皇后的位置会限制白皇后的放置,反之亦然。对于n×n的棋盘,我们需要计算所有满足条件的放置方法总数。
1.2 解决思路:分阶段深度优先搜索
我采用的解决方案是分两个阶段进行深度优先搜索(DFS):
- 第一阶段:枚举所有合法的黑皇后放置方式
- 第二阶段:对于每一种黑皇后的放置方式,计算对应的白皇后合法放置方式的数量
这种分治策略有效降低了问题的复杂度。具体实现时,我使用了三个辅助数组来快速判断位置是否可用:
- col_used:记录某列是否已被占用
- diag1:记录从左上到右下的对角线是否被占用
- diag2:记录从右上到左下的对角线是否被占用
提示:对于n×n棋盘,从左上到右下的对角线共有2n-1条,可以通过row-col+n-1来唯一标识每条对角线;从右上到左下的对角线也可以通过row+col来唯一标识。
1.3 关键代码解析
让我们深入看看黑皇后搜索的核心代码:
cpp复制void black_track(int row, vector<bool>& col_used, vector<bool>& diag1,
vector<bool>& diag2, vector<int>& black_pos) {
if(row == n) {
// 当黑皇后放置完成,开始计算白皇后放置方式
vector<bool> white_col(n, false);
vector<bool> white_diag1(2*n-1, false);
vector<bool> white_diag2(2*n-1, false);
int res = white_track(0, white_col, white_diag1, white_diag2, black_pos);
total += res;
return;
}
for(int col = 0; col < n; col++) {
if(board[row][col] == 0 || col_used[col] ||
diag1[row-col+n-1] || diag2[row+col]) {
