具有回溯的数独递归

时间:2013-08-12 16:05:28

标签: java recursion sudoku backtracking

我正在尝试使用递归回溯算法解决任何给定的数独谜题。我的数独求解器有两个问题。首先,它解决了这个难题,然而它在这个过程中进行了补偿并解决了它(解决了大约4718个recurses并且由于某种原因继续进行另外10000次左右的补救)。第二个问题源于我试图解决这个问题。我找到它后使用全局矩阵解决方案来保存解决方案,验证我是使用isSolved方法找到它的,如下所示:

  public static boolean isSolved(int[][]puzzle){
            for(int i = 0; i<9; i++){  //y rotation
                    for(int j = 0; j<8; j++){
                            if(puzzle[i][j]==0){
                                    return false;
                            }
                    }
            }
            return true;
    }

其中,在我的谜题中,一个带有0的块相当于它是空的。然而,这似乎也被重置,但是我无法找到重置的位置。我应该看的任何指针或建议或指针?

这是我的求解方法,我注释了重要的行

  public static int[][] solve(int[][]puzzle, int x, int y){
            System.out.println("RecrDepth:  " + recDepth);
            recDepth++;
            //using backtracking for brute force power of the gods(norse cause they obviously most b.a.
            ArrayList<Integer> list = new ArrayList<Integer>();
            //next for both  x and y
            int nextx = getNextx(x);
            int nexty = getNexty(x, y);
            while(puzzle[y][x] != 0){  //progress until blank space
                    x = nextx;
                    y = nexty;
                    if(isSolved(puzzle)){
                            System.out.println("resetting solution improperly");
                            solution = puzzle;
                            return puzzle;
                    }
                    nextx = getNextx(x);
                    nexty = getNexty(x, y);
            }
            for(int i = 1; i<10; i++){
                    if(isTrue(puzzle, y, x, i))  //isTrue checks column, row and box so we dont go down unnecessary paths
                            list.add(i);
            }
            for(int i=0; i<list.size(); i++){  //iterating through options in open squre recursing for each one
                    puzzle[y][x]= list.get(i);
                    if(isSolved(puzzle)){
                            System.out.println("Resetting Solution");  //appears to reset solution here but only once that I see in print out
                            solution = puzzle;
                            return puzzle;
                    }
                    System.out.print("=");
                    puzzle = solve(puzzle, nextx, nexty);
                    puzzle[y][x] = 0;//clear spot upon backtracking THIS WAS WHAT I WAS MISSIN
            }
            return puzzle;
    }

再次感谢您的时间,完整的代码和readin文件位于wechtera / ssolverOO的github上,它是ssolver.java文件,readin是ssolverin.txt

1 个答案:

答案 0 :(得分:3)

如果我正确理解了你的代码,问题似乎在于递归没有得到很好的实现,即使你的程序找到了正确的答案之后你的程序将继续循环最后一个for循环。

例如,假设在第一个空白方块中,正确的数字是4.但是您的程序正在考虑的可能的数字列表(在那个时间点)是{2,4,6,7}。在这种情况下,它似乎发生的是,它会在4处找到正确的答案,并且它将生成正确的输出。但它仍然会检查6和7.而且由于它(当然)无法找到任何答案,它会将输入留空,让你回到原来的电路板上。

现在,虽然我认为你在某种程度上在设置全局变量以存储实际答案方面有正确的想法。问题是你没有生成数组的副本,而只是将指针(引用)复制到它。

您可以简单地创建一个复制方法来实际复制整个数组,但请记住,即使您确实生成了正确的答案,您的算法仍然会不必要地循环并浪费时间。

作为参考,这是我写的解决方法,其中我的isValid()方法等同于你的isTrue():

public static final int SIZE = 9;

public static boolean solve(int[][] s) {

    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (s[i][j] != 0) {
                continue;
            }
            for (int num = 1; num <= SIZE; num++) {
                if (isValid(num, i, j, s)) {
                    s[i][j] = num;
                    if (solve(s)) {
                        return true;
                    } else {
                        s[i][j] = 0;
                    }
                }
            }
            return false;
        }
    }
    return true;
}