且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

对八皇后的回溯感到困惑

更新时间:2023-11-20 15:07:40

请考虑您的初衷:

+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

首次调用函数时,该算法在第0列和第0行放置一个女王/王后,因为您使用col = 0进行了调用,并且因为for (int i = 0; i < N; i++)从0开始.您的面板变成了

When you first call your function, the algorithm places a queen at column 0 and line 0 because you call it with col = 0 and because the for (int i = 0; i < N; i++) starts at 0. Your board becomes

+---+---+---+---+---+---+---+---+
| Q |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

然后,使用col = 1递归调用该函数,因此您将尝试在col=1line=0处放置一个女王.您会得到一个不可能的放置位置,因为女王之间可能会互相影响,因此您继续执行for (int i = 0; i < N; i++)循环并最终成功在col=1line=2处放置了女王之后,您将获得此木板:

Then, you call the function recursively, with col = 1, so you'll attempt to place a queen at col=1 and line=0. You get an impossible placement because the queens could take each other, so you continue the for (int i = 0; i < N; i++) loop and eventually succeed in placing a queen at col=1 and line=2, you get this board:

+---+---+---+---+---+---+---+---+
| Q |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   | Q |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

现在您继续执行此操作,每次增加col.最终,您将进入此论坛:

Now you keep doing this, incrementing col every time. Eventually, you'll get to this board:

+---+---+---+---+---+---+---+---+
| Q |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   | Q |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   | Q |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   | Q |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   | Q |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   | Q |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   | Q |   |
+---+---+---+---+---+---+---+---+

您在这里遇到了问题,因为此委员会不允许在第7列中加入女王位置.您必须回溯.发生的情况是,递归函数仅在尝试了列中的所有位置且未找到任何位置之后才达到return false;.当该函数返回false时,上一个函数调用将在该行上恢复执行

You have a problem here, because this board doesn't admit a queen position in column 7. You'll have to backtrack. What happens is that the recursive function only reaches return false; after all positions in a column were attempted and no position was found. When the function returns false, the previous function call will resume execution on the line

if ( solveNQUtil(board, col + 1) == true )

由于调用返回true,因此将执行for循环主体的其余部分,i将递增,并且算法将保持尝试位置.可以将其视为嵌套的for循环的巨大集合:

Since the call returned true, the rest of the for loop's body will be executed, i will be incremented and the algorithm will keep trying positions. Think of this as a gigantic set of nested for loop:

for(int i = 0; i < 8; ++i) {
  for(int j = 0; j < 8; ++j) {

    //Snip 6 other fors

    board[0, i] = 1;
    board[1, j] = 1;

    //Snip

    if(isValid(board)) return board;

    //Snip clean up
  }
}

您将其替换为递归函数调用.这说明回溯"实际上只是让先前的递归级别迭代到下一次尝试.在这种情况下,这意味着尝试一个新位置,而在其他应用程序中将尝试下一个生成的移动.

That you replace with recursive function calls. This illustrates that "backtracking" is really just letting the previous recursive level iterate to its next attempt. In this case, it means trying a new position while in other applications it would be to attempt the next generated move.

我认为您需要了解的是,当您再次调用同一函数时,上一个递归调用的状态不会丢失.当您到达线路

I think what you need to understand is that the state of the previous recursive call is not lost when you call the same function again. When you reach the line

if ( solveNQUtil(board, col + 1) == true )

当前函数的状态仍在堆栈上,并为对solveNQUtil的新调用创建新的堆栈框架.当该函数返回时,上一个函数可以继续执行,在这种情况下,可以增加尝试将皇后放置在哪一行的代码.

The state of the current function is still on the stack and a new stack frame is created for the new call to solveNQUtil. When that function returns, the previous one can continue its execution and, in this case, increment which line it's attempting to place the queen in.

希望这会有所帮助.***的办法是将问题减少到较小的范围(例如,较少的皇后区),并使用调试器逐步执行.

Hope this helps. The best way to wrap your head around this stuff is to reduce your problem to a smaller domain (say a smaller amount of queens) and step through the execution using a debugger.