N queen problem
!!! question
根据国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。给定 $n$ 个皇后和一个 $n \times n$ 大小的棋盘,寻找使得所有皇后之间无法相互攻击的摆放方案。
As shown in the figure below, when n = 4 n = 4n=4 , a total of two solutions can be found. From the perspective of the backtracking algorithm,n × nn \times nn×A chessboard of size n has a total of n 2 n^2n2 grids, giving all choiceschoices
. In the process of placing queens one by one, the chessboard state is constantly changing, and the chessboard at each moment is the statestate
.
The figure below shows the three constraints of this question: multiple queens cannot be in the same row, the same column, or the same diagonal . It is worth noting that diagonals are divided into two types: main diagonals \
and sub-diagonals /
.
Row-by-row placement strategy
The number of queens and the number of rows on the chessboard are both nn , so we can easily get an inference:each row of the chessboard allows and only allows one queen to be placed.
That is, we can adopt a row-by-row placement strategy: starting from the first row, placing a queen in each row until the end of the last row.
As shown in the figure below, it is 4 4Row-by-row placement process for the 4- queen problem. Due to frame limitations, the figure below only expands one of the search branches in the first row, and prunes solutions that do not satisfy column constraints and diagonal constraints.
Essentially, the row-by-row placement strategy acts as a pruner , which avoids all search branches where multiple queens appear in the same row.
Column and diagonal pruning
In order to satisfy the column constraints, we can use a length of nnBoolean array of ncols
records whether each column has a queen. Before each placement decision, wecols
prune the columns that already have queens and dynamically updatecols
the state during backtracking.
So, how to deal with diagonal constraints? Suppose the row and column index of a certain grid on the chessboard is (row, col) (row, col)(row,co l ) , select a main diagonal in the matrix, we find that the row index minus column index of all cells on the diagonal are equal, that is, row − col row - col of all cells on the diagonalrow−co l is a constant value.
That is to say, if the two grids satisfy row 1 − col 1 = row 2 − col 2 row_1 - col_1 = row_2 - col_2row1−col1=row2−col2, then they must be on the same main diagonal. Using this rule, we can use the array shown in the figure below diag1
to record whether there is a queen on each main diagonal.
In the same way, row + col row + col of all grids on the sub-diagonalrow+col is a constant value . We can also use arraysdiag2
to handle subdiagonal constraints.
Code
Please note that nnrow − col row - col in n- dimensional square matrixrow−The range of co l is[ − n + 1 , n − 1 ] [-n + 1, n - 1][−n+1,n−1] , r o w + c o l row + col row+The range of co l is[ 0 , 2 n − 2 ] [0, 2n − 2][0,2 n−2 ] , so the number of main diagonals and sub-diagonals is2 n − 1 2n - 12 n−1 , that is, the lengths of the arraysdiag1
anddiag2
are both2 n − 1 2n - 12 n−1 。
=== “Python”
```python title="n_queens.py"
[class]{}-[func]{backtrack}
[class]{}-[func]{n_queens}
```
=== “C++”
```cpp title="n_queens.cpp"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “Java”
```java title="n_queens.java"
[class]{n_queens}-[func]{backtrack}
[class]{n_queens}-[func]{nQueens}
```
=== “C#”
```csharp title="n_queens.cs"
[class]{n_queens}-[func]{backtrack}
[class]{n_queens}-[func]{nQueens}
```
=== “Go”
```go title="n_queens.go"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “Swift”
```swift title="n_queens.swift"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “JS”
```javascript title="n_queens.js"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “TS”
```typescript title="n_queens.ts"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “Dart”
```dart title="n_queens.dart"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “Rust”
```rust title="n_queens.rs"
[class]{}-[func]{backtrack}
[class]{}-[func]{n_queens}
```
=== “C”
```c title="n_queens.c"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
=== “Zig”
```zig title="n_queens.zig"
[class]{}-[func]{backtrack}
[class]{}-[func]{nQueens}
```
Place nn row by rown times, considering column constraints, there arennn、 n − 1 n-1 n−1、 … \dots …、 2 2 2、 1 1 1 choice,so the time complexity is O ( n ! ) O(n!)O ( n !) . In fact, pruning based on diagonal constraints can also significantly reduce the search space, so the search efficiency is often better than the above time complexity.
Arrays state
use O ( n 2 ) O(n^2)O ( n2 )Space, arraycols
,diags1
anddiags2
all useO ( n ) O (n)O ( n ) space. The maximum recursion depth isnnn , useO ( n ) O(n)O ( n ) stack frame space. Therefore,the space complexity is O ( n 2 ) O(n^2)O ( n2) 。