【问题标题】:Problem with recursive backtracking - Sudoku Solving Example递归回溯问题 - 数独求解示例
【发布时间】:2014-03-21 00:00:36
【问题描述】:

最近我一直在尝试自学一些递归,以更好地理解这个过程。虽然我了解基本的递归技术,但我仍然对递归回溯的想法感到困惑。为了帮助解决这个问题,我尝试编写一种方法,在给定一个二维数组和两个整数 r 和 c 时求解数独求解器,它们用于表示当前列和行。

我相信我已经正确设置了所有东西,但我无法完全弄清楚如何处理“解开”,或者在我的初始方法调用达到最终的基本情况后会发生什么。

截至目前,当我运行这个方法时,它只返回一个空的板,(除非之前有一个值,在这种情况下它保持不变)。我觉得我在方法末尾的“board[r][c] = 0”可能与此有关。

“digitsValid”方法对应于检查以确保棋盘上的当前位置是行、列和 3x3 子网格内的有效移动的方法。

任何帮助将不胜感激。

private boolean sudokuSolver(int[][] board, int r, int c) {

    if(c > 8) {
        c = 0;
        r = r + 1;
    }

    if(r > 8) {
        return true;
    }

    if(board[r][c] != 0) {
        sudokuSolver(board, r, c + 1);
    } else {
        for(int i = 1; i <= 9; i++) {
            if(digitsValid(board, r, c)) {
                board[r][c] = i;    
                if(sudokuSolver(board, r, c + 1)) {
                    return true;
                }
            }
        }
    }

    board[r][c] = 0;
    return false;
}

【问题讨论】:

  • 首先进入递归方法的板子是什么样子的?

标签: java recursion


【解决方案1】:

我认为您最初的评估是正确的。递归方法听起来令人困惑,但可以这样想:

public class RecursiveTest{

public static void main(String[] args){
    int x = 5;
    recursiveMethod(x);
}


public static void recursiveMethod(int i){
    System.out.println("Method just started for i = " + i);
    if(i > 0)
        recursiveMethod(i - 1);
    System.out.println("Method just ended for i = " + i);
}
}

产生以下输出:

Method just started for i = 5
Method just started for i = 4
Method just started for i = 3
Method just started for i = 2
Method just started for i = 1
Method just started for i = 0
Method just ended for i = 0
Method just ended for i = 1
Method just ended for i = 2
Method just ended for i = 3
Method just ended for i = 4
Method just ended for i = 5

说明

递归方法与任何其他方法并没有什么不同。它执行一些代码,在某些时候调用一个方法,运行该方法,然后继续运行其余代码并在任何其他方法可以完成的地方完成。

唯一的区别是方法调用是对自身的调用。这与您将相同的方法复制粘贴 5 次并将其命名为不同的名称然后将它们“菊花链”在一起时的效果相同。

在上面的示例中,原始值为 5,它打印出它开始 for i=5,然后以 4 的值运行相同的方法。打印出来,然后运行 ​​3 等等。一旦达到最终i = 0 的值 if 语句失败,因此它停止了递归调用。我们当前处于 (i = 0) 的方法通过写入 Method just ended for i = 0 结束,然后在 i = 1 时返回调用方法,并以相同的方式返回。

您的代码

我不太确定你在这里发生了什么。你的例子有用吗?我想看看isValid() 方法,但是你有以下代码:

for(int i = 1; i <= 9; i++) {   // Runs the following code 9 times.
    if(digitsValid(board, r, c)) {   // if true once, true every time
        board[r][c] = i;    
        if(sudokuSolver(board, r, c + 1)) {  // this is a totally separate method
            return true;
        }
    }
}

您的循环运行了 9 次。它后面的 if 语句永远不会改变。其中的值不会在循环内编辑,因此如果它在 i = 1 时计算为true,那么它将在 for 循环的所有 9 次迭代中计算为 true。这意味着board[r][c] 的值将在 9 结束。

从表面上看,返回 false 的唯一方法是在调用该方法时数组中已经存储了无效数字。

【讨论】: