我的回溯算法出了什么问题?

时间:2013-06-22 22:41:26

标签: java algorithm sudoku backtracking

我正在制作一个生成数独谜题的程序。我试图使用回溯算法来执行此操作,但我的程序无法正常工作。该程序只是无限运行,永远不会返回解决方案。我不知道它只是一个小问题,还是我误解了如何编写回溯算法。

package sudoku;

import java.util.Random;

public class Puzzle {

    // 9x9 puzzle
    private int puzzle[][] = new int[9][9];

    // generate a completely solved sudoku board
    public int[][] generate() {

        Random gen = new Random();

        // add each number to the board square by square
        for (int y = 0; y < 9; y++) {
            for (int x = 0; x < 9; x++) {

                // generate random number 1-9
                int num = gen.nextInt(9) + 1;

                int count = 0;
                boolean valid = false;

                while (valid == false) {

                    // check if number is valid
                    if (checkRow(num, x) && checkCol(num, y)
                            && checkSection(num, x, y)) {

                        // add number to the board
                        puzzle[x][y] = num;

                        // exit loop, move on to next square
                        valid = true;

                    } else {

                        // try next number
                        if (num == 9) {
                            num = 1;
                        } else {
                            num++;
                        }

                        // increase counter.
                        count++;

                        // if counter reached 9, then all numbers were tried and
                        // none were valid, begin backtracking
                        if (count == 9) {

                            // go back 1 square
                            if (x == 0) {
                                x = 8;
                                y--;
                            } else {
                                x--;
                            }

                            // empty square
                            puzzle[x][y] = 0;

                            //reset count
                            count = 0;

                        }

                    }

                }
            }
        }

        return puzzle;
    }

    // check each element of the row for num, if num is found return false
    private boolean checkRow(int num, int row) {

        for (int i = 0; i < 9; i++) {
            if (puzzle[row][i] == num) {
                return false;
            }
        }

        return true;
    }

    // check each element of the column for num, if num is found return false
    private boolean checkCol(int num, int col) {

        for (int i = 0; i < 9; i++) {
            if (puzzle[i][col] == num) {
                return false;
            }
        }

        return true;
    }

    // check each element of the section for num, if num is found return false
    private boolean checkSection(int num, int xPos, int yPos) {

        int[][] section = new int[3][3];
        section = getSection(xPos, yPos);

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (section[i][j] == num)
                    return false;
            }
        }
        return true;

    }

    // return the 3x3 section the given coordinates are in
    private int[][] getSection(int xPos, int yPos) {

        int[][] section = new int[3][3];
        int xIndex = 3 * (xPos / 3);
        int yIndex = 3 * (yPos / 3);

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                section[i][j] = puzzle[xIndex + i][yIndex + j];
            }
        }

        return section;

    }
}

2 个答案:

答案 0 :(得分:1)

可能会发生许多问题。我将举一个例子。

回溯不起作用的主要原因是因为你没有做回溯。你只返回树中的一个状态,回溯意味着你检查一个子树的所有可能性然后(如果没有有效)你忽略那个子树,无论它有多高。

让我们看看。你的方法是&#34;将所有数字排成一行,并希望广场完成。如果处理当前方块时出错,请清除前一个方格&#34;。

一开始没问题,获取第一行不会导致错误。但想想你完成前8行的可能性,有类似的东西:

1
2
3
----
4
5
6
---
79
832|179|456     
x

x没有有效值。你的算法有什么作用?回去尝试改变6!不出所料,这将以6替换6结束,并再次尝试将值设置为x

我在互联网上找到的Sudokus生成器没有回溯,只需采用有效的解决方案并对其进行一系列更改,所有更改都会带来有效的解决方案(有关详细信息,请咨询谷歌)。

如果你想使用回溯,你应该在每一步扫描数据是否仍然可以解决(或者至少,那不是&#34;破坏&#34;)。并且有办法不重复不可解决的组合。

此外,试图按顺序排列数字似乎(这是一种观点)在开始时添加一个过于强大的约束。填充前两行很容易,但它会调整整个解决方案(注意填充第一行不会影响它!:-D)。

答案 1 :(得分:0)

我不认为这是解决问题的好方法;遗憾的是,我没有为你提供解决方案,但我确实看到count == 9,你改变x and y,这不一定是好事。但是,您没有提供终止while(!valid)循环的方法。您需要将valid更改为true才能实际回溯;但是,这不会使该方法有效。