-1

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

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;

    }
}
4

2 回答 2

1

可能会发生许多问题。我只是举个例子。

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

让我们来看看。您的方法是“将所有数字排成一行,并希望方块完成。如果处理当前方块出错,请清除前一个方块”。

一开始没问题,拿到第一行就不会出错。但是想想你已经完成了前 8 行的可能性,如下所示:

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

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

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

如果你想使用回溯,在每一步你都应该扫描数独是否仍然可以解决(或者至少,这不是“坏的”)。并且有办法不重复不可解决的组合。

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

于 2013-06-22T23:26:23.627 回答
0

我认为这不是解决问题的好方法。不幸的是,我没有适合你的解决方案,但我确实看到,一旦count == 9你改变x and y了,这并不是一件好事。尽管如此,您并没有提供终止while(!valid)循环的方法。您需要更改validtrue实际回溯;但是,这不会使该方法起作用。

于 2013-06-22T23:57:42.893 回答