题目来源:https://leetcode.com/problems/n-queens/
问题描述
51. N-Queens
Hard
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.
Example:
Input: 4
Output: [
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
------------------------------------------------------------
题意
N皇后问题。在N×N的棋盘上放N个皇后,使得她们不会互相攻击。
------------------------------------------------------------
思路
dfs深搜。一开始我的思路是遍历每一个单元格,考察是否可以放皇后,再用两种剪枝方法(如果有一整行不能放皇后则返回;如果一行已经放了皇后则跳到下一行)进行剪枝。
后来在同学的提醒下,想到由于每行只能放一个皇后,所以可以用一个onehot的mask表示每行皇后的位置,然后用位运算可以方便地实现搜索。
另外需要注意位运算的优先级比==低,要勤加括号~
------------------------------------------------------------
代码
【对每个单元格进行搜索的代码】
class Solution {
private List<List<String>> ans = new LinkedList<>();
private int n;
private boolean[][] board;
private boolean[] row_mark;
private boolean[] col_mark;
private boolean[] sub_mark;
private boolean[] sum_mark;
private boolean[] edit_row;
private int cnt;
private void init(int n)
{
this.n = n;
this.cnt = 0;
this.board = new boolean[n][n];
this.row_mark = new boolean[n];
this.col_mark = new boolean[n];
this.sub_mark = new boolean[2*n-1];
this.sum_mark = new boolean[2*n-1];
this.edit_row = new boolean[n];
}
private static List<String> board2ans(boolean[][] board)
{
List<String> ret = new ArrayList<String>();
for (boolean[] row: board)
{
StringBuilder sb = new StringBuilder();
for (boolean item: row)
{
if (item)
{
sb.append("Q");
}
else
{
sb.append(".");
}
}
ret.add(sb.toString());
}
return ret;
}
private void dfs(int x, int y)
{
if (x == this.n)
{
if (this.cnt == this.n)
{
ans.add(board2ans(this.board));
}
return;
}
if (x > 0 && !this.edit_row[x-1])
{
return;
}
if (this.edit_row[x])
{
dfs(x+1, 0);
return;
}
if (!this.row_mark[x] && !this.col_mark[y] && !this.sub_mark[x-y+n-1] && !this.sum_mark[x+y])
{
this.board[x][y] = true;
this.row_mark[x] = true;
this.col_mark[y] = true;
this.sub_mark[x-y+n-1] = true;
this.sum_mark[x+y] = true;
this.edit_row[x] = true;
this.cnt++;
if (y == this.n-1)
{
dfs(x+1, 0);
}
else
{
dfs(x, y+1);
}
this.board[x][y] = false;
this.row_mark[x] = false;
this.col_mark[y] = false;
this.sub_mark[x-y+n-1] = false;
this.sum_mark[x+y] = false;
this.edit_row[x] = false;
this.cnt--;
}
if (y == this.n-1)
{
dfs(x+1, 0);
}
else
{
dfs(x, y+1);
}
}
public List<List<String>> solveNQueens(int n) {
if (n == 0)
{
return new LinkedList() {
{
add(Collections.emptyList());
}
};
}
init(n);
dfs(0, 0);
return this.ans;
}
}
【对每行的mask进行搜索的代码】
class Solution {
private List<List<String>> ans = new LinkedList<>();
private int n;
private int[] mask;
private boolean[] col_mark;
private boolean[] sub_mark;
private boolean[] sum_mark;
private void init(int n)
{
this.n = n;
this.mask = new int[n];
this.col_mark = new boolean[n];
this.sub_mark = new boolean[2*n-1];
this.sum_mark = new boolean[2*n-1];
}
private List<String> mask2ans(int[] mask)
{
List<String> ret = new ArrayList<String>();
int N = mask.length, i = 0, bit = 1;
for (int row: mask)
{
StringBuilder sb = new StringBuilder();
bit = 1;
for (i=0; i<N; i++)
{
if ((row & bit) == 0)
{
sb.append(".");
}
else
{
sb.append("Q");
}
bit <<= 1;
}
ret.add(sb.toString());
}
return ret;
}
public void dfs(int x)
{
if (x == n)
{
this.ans.add(mask2ans(mask));
return;
}
int y = 0, bit = 1;
for (y=0; y<this.n; y++)
{
if (!this.col_mark[y] && !this.sub_mark[x-y+n-1] && !this.sum_mark[x+y])
{
this.mask[x] = bit;
this.col_mark[y] = true;
this.sub_mark[x-y+n-1] = true;
this.sum_mark[x+y] = true;
dfs(x+1);
this.col_mark[y] = false;
this.sub_mark[x-y+n-1] = false;
this.sum_mark[x+y] = false;
}
bit <<= 1;
}
}
public List<List<String>> solveNQueens(int n) {
if (n == 0)
{
return new LinkedList() {
{
add(Collections.emptyList());
}
};
}
init(n);
dfs(0);
return ans;
}
}