DFS解决数独

时间:2016-12-13 21:55:08

标签: java depth-first-search sudoku

我正在使用DFS算法处理16 * 16数独问题。 Java代码如下所示:

    public class dfs {

    public boolean dfs(int[][] puzzle,int i,int j){
        if(i==15&&j>=16) return true;
        if(j==16){
            //System.out.println(String.valueOf(i));

            return dfs(puzzle,i+1,0);  //{j=0; i++;
        }
        if(puzzle[i][j]!=-1){
            return dfs(puzzle,i,j+1);  //next cell in the same row
        }
        else{
            for(int num=1;num<=16;num++){
                //System.out.println("trying"+i+","+j+","+num);
                if(valid(puzzle,i,j,num)){
                    //System.out.println(String.valueOf(num));
                    puzzle[i][j]=num;
                    if(dfs(puzzle,i,j+1)){
                        return true;

                    }
                }
                //else return false;
            }
        }
        return false;
    }
    public boolean valid(int[][] puzzle,int x,int y,int num){
        for(int i=0;i<16;i++){
            if(puzzle[i][y]==num) {
                //System.out.println("a");
                return false;
            }
        }
        for(int j=0;j<16;j++){
            if(puzzle[x][j]==num){
                //System.out.println("b");
                return false;
            }
        }
        int c=(x/4)*4;
        int r=(y/4)*4;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if(puzzle[c+i][r+j]==num){
                    //System.out.println("c");
                    return false;
                }
            }

        }
        return true;

    }
}

主要方法是:

 public static void main(String[] args) {
        sudoku sudokuPuzzleGenerator = new sudoku();
        long start = System.currentTimeMillis();
        int numOfSudokuMatrix = 1;
        List<int[][]> sudoku = new ArrayList<int[][]>();
        for (int count = 1; count <= numOfSudokuMatrix; count++) {
            int[][] randomMatrix = sudokuPuzzleGenerator.generatePuzzleMatrix();
            int hole = 81;
            while (hole > 0) {
                Random randomGenerator = new Random();
                int x = randomGenerator.nextInt(16);
                int y = randomGenerator.nextInt(16);
                if (randomMatrix[x][y] != -1) {
                    randomMatrix[x][y] = -1;
                    hole--;
                }
            }
            for(int i=0;i<16;i++){
                for(int j=0;j<16;j++){
                    System.out.print(randomMatrix[i][j] + " ");
                }
                System.out.println();
            }
            sudoku.add(randomMatrix);
        }
        System.out.println();


        long start2 = System.currentTimeMillis();
        for (int[][] p:sudoku) {
            dfs d=new dfs();
            boolean b=d.dfs(p,0,0);
            for (int rowNum = 0; rowNum < 16; rowNum++) {
                for (int colNum = 0; colNum < 16; colNum++) {
                    System.out.print(p[rowNum][colNum] + " ");
                }
                System.out.println();
            }
        }
        Long end2 = System.currentTimeMillis();
        Long time2 = end2 - start2;
        System.out.println("It took: " + time2  + " milliseconds.");

    }

当我运行代码时,它通常在填充所有空格之前终止,在拼图中留下许多-1。我不确定问题出在哪里。我会非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

没关系,但这可能被归类为backtracking问题,而不是搜索。无论如何,我认为就是这样,但没有generatePuzzleMatrix方法就很难测试。检查给定单元格中的每个可能的数字后,如果找不到答案(按基本情况),则需要将单元格设置回-1。

for(int num=1;num<=16;num++){
    if(valid(puzzle,i,j,num)){
        puzzle[i][j]=num;
        if(dfs(puzzle,i,j+1)){
            return true;
        }
    }
}
puzzle[i][j] = -1;

如果不将此值设置回-1,即使您没有找到答案,也会将这些值设置为最高有效值。递归算法的未来迭代将跳过该值,因为它们认为它是正确的。因此,您的循环将结束而不测试所有可能性并找到答案。希望这能为你做到。

评论回复

是的,我同意至少有一个解决方案。我相信问题是你的循环在你实际测试所有可能性之前就结束了。递归调用需要在测试完所有可能性后再将其设置回来。在递归堆栈中的任意深度,假设您向网格添加有效数字。在该阶段有效的数字并不意味着它处于正确的位置。你可以创造一个涟漪效应。虽然它目前对该特定数字有效,但您无意中提出了基于您目前填写的单元格的任何解决方案的可能性。一旦遇到这种情况,就会出现问题。您的网格将保留最近设置的值,并且您永远不会尝试将其设置为其他任何值(因为您有一个忽略值的条件!= -1)。