mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-31 04:17:14 +00:00
deploy
This commit is contained in:
@@ -3604,38 +3604,38 @@
|
||||
<h1 id="134-n-queens-problem">13.4 n queens problem<a class="headerlink" href="#134-n-queens-problem" title="Permanent link">¶</a></h1>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">Question</p>
|
||||
<p>According to the rules of chess, a queen can attack pieces in the same row, column, or on a diagonal line. Given <span class="arithmatex">\(n\)</span> queens and an <span class="arithmatex">\(n \times n\)</span> chessboard, find arrangements where no two queens can attack each other.</p>
|
||||
<p>According to the rules of chess, a queen can attack pieces in the same row, column, or diagonal line. Given <span class="arithmatex">\(n\)</span> queens and an <span class="arithmatex">\(n \times n\)</span> chessboard, find arrangements where no two queens can attack each other.</p>
|
||||
</div>
|
||||
<p>As shown in Figure 13-15, when <span class="arithmatex">\(n = 4\)</span>, there are two solutions. From the perspective of the backtracking algorithm, an <span class="arithmatex">\(n \times n\)</span> chessboard has <span class="arithmatex">\(n^2\)</span> squares, presenting all possible choices <code>choices</code>. The state of the chessboard <code>state</code> changes continuously as each queen is placed.</p>
|
||||
<p>As shown in Figure 13-15, there are two solutions when <span class="arithmatex">\(n = 4\)</span>. From the perspective of the backtracking algorithm, an <span class="arithmatex">\(n \times n\)</span> chessboard has <span class="arithmatex">\(n^2\)</span> squares, presenting all possible choices <code>choices</code>. The state of the chessboard <code>state</code> changes continuously as each queen is placed.</p>
|
||||
<p><a class="glightbox" href="../n_queens_problem.assets/solution_4_queens.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Solution to the 4 queens problem" class="animation-figure" src="../n_queens_problem.assets/solution_4_queens.png" /></a></p>
|
||||
<p align="center"> Figure 13-15 Solution to the 4 queens problem </p>
|
||||
|
||||
<p>Figure 13-16 shows the three constraints of this problem: <strong>multiple queens cannot be on the same row, column, or diagonal</strong>. It is important to note that diagonals are divided into the main diagonal <code>\</code> and the secondary diagonal <code>/</code>.</p>
|
||||
<p>Figure 13-16 shows the three constraints of this problem: <strong>multiple queens cannot occupy the same row, column, or diagonal</strong>. It is important to note that diagonals are divided into the main diagonal <code>\</code> and the secondary diagonal <code>/</code>.</p>
|
||||
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_constraints.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Constraints of the n queens problem" class="animation-figure" src="../n_queens_problem.assets/n_queens_constraints.png" /></a></p>
|
||||
<p align="center"> Figure 13-16 Constraints of the n queens problem </p>
|
||||
|
||||
<h3 id="1-row-by-row-placing-strategy">1. Row-by-row placing strategy<a class="headerlink" href="#1-row-by-row-placing-strategy" title="Permanent link">¶</a></h3>
|
||||
<p>As the number of queens equals the number of rows on the chessboard, both being <span class="arithmatex">\(n\)</span>, it is easy to conclude: <strong>each row on the chessboard allows and only allows one queen to be placed</strong>.</p>
|
||||
<p>As the number of queens equals the number of rows on the chessboard, both being <span class="arithmatex">\(n\)</span>, it is easy to conclude that <strong>each row on the chessboard allows and only allows one queen to be placed</strong>.</p>
|
||||
<p>This means that we can adopt a row-by-row placing strategy: starting from the first row, place one queen per row until the last row is reached.</p>
|
||||
<p>Figure 13-17 shows the row-by-row placing process for the 4 queens problem. Due to space limitations, the figure only expands one search branch of the first row, and prunes any placements that do not meet the column and diagonal constraints.</p>
|
||||
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_placing.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Row-by-row placing strategy" class="animation-figure" src="../n_queens_problem.assets/n_queens_placing.png" /></a></p>
|
||||
<p align="center"> Figure 13-17 Row-by-row placing strategy </p>
|
||||
|
||||
<p>Essentially, <strong>the row-by-row placing strategy serves as a pruning function</strong>, avoiding all search branches that would place multiple queens in the same row.</p>
|
||||
<p>Essentially, <strong>the row-by-row placing strategy serves as a pruning function</strong>, eliminating all search branches that would place multiple queens in the same row.</p>
|
||||
<h3 id="2-column-and-diagonal-pruning">2. Column and diagonal pruning<a class="headerlink" href="#2-column-and-diagonal-pruning" title="Permanent link">¶</a></h3>
|
||||
<p>To satisfy column constraints, we can use a boolean array <code>cols</code> of length <span class="arithmatex">\(n\)</span> to track whether a queen occupies each column. Before each placement decision, <code>cols</code> is used to prune the columns that already have queens, and it is dynamically updated during backtracking.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>Note that the origin of the chessboard is located in the upper left corner, where the row index increases from top to bottom, and the column index increases from left to right.</p>
|
||||
<p>Note that the origin of the matrix is located in the upper left corner, where the row index increases from top to bottom, and the column index increases from left to right.</p>
|
||||
</div>
|
||||
<p>How about the diagonal constraints? Let the row and column indices of a cell on the chessboard be <span class="arithmatex">\((row, col)\)</span>. By selecting a specific main diagonal, we notice that the difference <span class="arithmatex">\(row - col\)</span> is the same for all cells on that diagonal, <strong>meaning that <span class="arithmatex">\(row - col\)</span> is a constant value on that diagonal</strong>.</p>
|
||||
<p>Thus, if two cells satisfy <span class="arithmatex">\(row_1 - col_1 = row_2 - col_2\)</span>, they are definitely on the same main diagonal. Using this pattern, we can utilize the array <code>diags1</code> shown in Figure 13-18 to track whether a queen is on any main diagonal.</p>
|
||||
<p>Similarly, <strong>the sum <span class="arithmatex">\(row + col\)</span> is a constant value for all cells on a secondary diagonal</strong>. We can also use the array <code>diags2</code> to handle secondary diagonal constraints.</p>
|
||||
<p>How about the diagonal constraints? Let the row and column indices of a certain cell on the chessboard be <span class="arithmatex">\((row, col)\)</span>. By selecting a specific main diagonal, we notice that the difference <span class="arithmatex">\(row - col\)</span> is the same for all cells on that diagonal, <strong>meaning that <span class="arithmatex">\(row - col\)</span> is a constant value on the main diagonal</strong>.</p>
|
||||
<p>In other words, if two cells satisfy <span class="arithmatex">\(row_1 - col_1 = row_2 - col_2\)</span>, they are definitely on the same main diagonal. Using this pattern, we can utilize the array <code>diags1</code> shown in Figure 13-18 to track whether a queen is on any main diagonal.</p>
|
||||
<p>Similarly, <strong>the sum of <span class="arithmatex">\(row + col\)</span> is a constant value for all cells on the secondary diagonal</strong>. We can also use the array <code>diags2</code> to handle secondary diagonal constraints.</p>
|
||||
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_cols_diagonals.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Handling column and diagonal constraints" class="animation-figure" src="../n_queens_problem.assets/n_queens_cols_diagonals.png" /></a></p>
|
||||
<p align="center"> Figure 13-18 Handling column and diagonal constraints </p>
|
||||
|
||||
<h3 id="3-code-implementation">3. Code implementation<a class="headerlink" href="#3-code-implementation" title="Permanent link">¶</a></h3>
|
||||
<p>Please note, in an <span class="arithmatex">\(n\)</span>-dimensional matrix, the range of <span class="arithmatex">\(row - col\)</span> is <span class="arithmatex">\([-n + 1, n - 1]\)</span>, and the range of <span class="arithmatex">\(row + col\)</span> is <span class="arithmatex">\([0, 2n - 2]\)</span>, thus the number of both main and secondary diagonals is <span class="arithmatex">\(2n - 1\)</span>, meaning the length of both arrays <code>diags1</code> and <code>diags2</code> is <span class="arithmatex">\(2n - 1\)</span>.</p>
|
||||
<p>Please note, in an <span class="arithmatex">\(n\)</span>-dimensional square matrix, the range of <span class="arithmatex">\(row - col\)</span> is <span class="arithmatex">\([-n + 1, n - 1]\)</span>, and the range of <span class="arithmatex">\(row + col\)</span> is <span class="arithmatex">\([0, 2n - 2]\)</span>. Consequently, the number of both main and secondary diagonals is <span class="arithmatex">\(2n - 1\)</span>, meaning the length of the arrays <code>diags1</code> and <code>diags2</code> is <span class="arithmatex">\(2n - 1\)</span>.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:14"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><input id="__tabbed_1_13" name="__tabbed_1" type="radio" /><input id="__tabbed_1_14" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Kotlin</label><label for="__tabbed_1_13">Ruby</label><label for="__tabbed_1_14">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3847,8 +3847,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Placing <span class="arithmatex">\(n\)</span> queens row-by-row, considering column constraints, from the first row to the last row there are <span class="arithmatex">\(n\)</span>, <span class="arithmatex">\(n-1\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(1\)</span> choices, using <span class="arithmatex">\(O(n!)\)</span> time. When recording a solution, it is necessary to copy the matrix <code>state</code> and add it to <code>res</code>, with the copying operation using <span class="arithmatex">\(O(n^2)\)</span> time. Therefore, <strong>the overall time complexity is <span class="arithmatex">\(O(n! \cdot n^2)\)</span></strong>. In practice, pruning based on diagonal constraints can significantly reduce the search space, thus often the search efficiency is better than the above time complexity.</p>
|
||||
<p>Array <code>state</code> uses <span class="arithmatex">\(O(n^2)\)</span> space, and arrays <code>cols</code>, <code>diags1</code>, and <code>diags2</code> each use <span class="arithmatex">\(O(n)\)</span> space. The maximum recursion depth is <span class="arithmatex">\(n\)</span>, using <span class="arithmatex">\(O(n)\)</span> stack space. Therefore, <strong>the space complexity is <span class="arithmatex">\(O(n^2)\)</span></strong>.</p>
|
||||
<p>Placing <span class="arithmatex">\(n\)</span> queens row-by-row, considering column constraints, from the first row to the last row, there are <span class="arithmatex">\(n\)</span>, <span class="arithmatex">\(n-1\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(1\)</span> choices, using <span class="arithmatex">\(O(n!)\)</span> time. When recording a solution, it is necessary to copy the matrix <code>state</code> and add it to <code>res</code>, with the copying operation using <span class="arithmatex">\(O(n^2)\)</span> time. Therefore, <strong>the overall time complexity is <span class="arithmatex">\(O(n! \cdot n^2)\)</span></strong>. In practice, pruning based on diagonal constraints can significantly reduce the search space, thus often the search efficiency is better than the aforementioned time complexity.</p>
|
||||
<p>Array <code>state</code> uses <span class="arithmatex">\(O(n^2)\)</span> space, and arrays <code>cols</code>, <code>diags1</code>, and <code>diags2</code> each use <span class="arithmatex">\(O(n)\)</span> space as well. The maximum recursion depth is <span class="arithmatex">\(n\)</span>, using <span class="arithmatex">\(O(n)\)</span> stack frame space. Therefore, <strong>the space complexity is <span class="arithmatex">\(O(n^2)\)</span></strong>.</p>
|
||||
|
||||
<!-- Source file information -->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user