Q:n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
示例:
输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
提示:皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一或七步,可进可退。(引用自 百度百科 - 皇后 )
A:
同I中的回溯法
private int result;
public int totalNQueens(int n) {
if (n <= 1)
return n;
ArrayList<Integer> l = new ArrayList<>();
result = 0;
help(0, n, l);
return result;
}
private void help(int row, int n, ArrayList<Integer> l) {
if (row == n) {
result++;
return;
}
for (int col = 0; col < n; col++) {
if (!l.contains(col)) {
if (!isDiagonal(l, col)) {
l.add(col);
help(row + 1, n, l);
l.remove(l.size() - 1);
}
}
}
}
private boolean isDiagonal(ArrayList<Integer> l, int col) {
int currRow = l.size();
for (int row = 0; row < l.size(); row++) {
if (Math.abs(currRow - row) == Math.abs(col - l.get(row))) {
return true;
}
}
return false;
}
2.如果是面试,上面那种就ok了。还有一种位运算的方法,(但我位运算学的一直不好,就没仔细看)
借鉴:使用 bitmap 回溯
public int backtrack(int row, int hills, int next_row, int dales, int count, int n) {
/**
row: 当前放置皇后的行号
hills: 主对角线占据情况 [1 = 被占据,0 = 未被占据]
next_row: 下一行被占据的情况 [1 = 被占据,0 = 未被占据]
dales: 次对角线占据情况 [1 = 被占据,0 = 未被占据]
count: 所有可行解的个数
*/
// 棋盘所有的列都可放置,
// 即,按位表示为 n 个 '1'
// bin(cols) = 0b1111 (n = 4), bin(cols) = 0b111 (n = 3)
// [1 = 可放置]
int columns = (1 << n) - 1;
if (row == n) // 如果已经放置了 n 个皇后
count++; // 累加可行解
else {
// 当前行可用的列
// ! 表示 0 和 1 的含义对于变量 hills, next_row and dales的含义是相反的
// [1 = 未被占据,0 = 被占据]
int free_columns = columns & ~(hills | next_row | dales);
// 找到可以放置下一个皇后的列
while (free_columns != 0) {
// free_columns 的第一个为 '1' 的位
// 在该列我们放置当前皇后
int curr_column = - free_columns & free_columns;
// 放置皇后
// 并且排除对应的列
free_columns ^= curr_column;
count = backtrack(row + 1,
(hills | curr_column) << 1,
next_row | curr_column,
(dales | curr_column) >> 1,
count, n);
}
}
return count;
}
public int totalNQueens(int n) {
return backtrack(0, 0, 0, 0, 0, n);
}