使用回溯在java中解决Sudoku问题

时间:2016-05-21 14:36:26

标签: java algorithm artificial-intelligence

我正在尝试使用java编写一个数独求解器。我已经使用了常见的回溯算法。但该程序无法正常工作(返回null)

这是代码

public class Sudoku {

    int[][] board;                                                              //Sudoku board


    public Sudoku() {                                                           //constructor
        this.board = new int[9][9];             
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                board[i][j]=0;
    }

    public Sudoku(int[][] board){                                               //constructor
        this.board=board;
    }


    public int[][] Solve(int[][] board){
        int i, j, k,l,val;                                                      //iterators 
        int empty=1;                                                            //empty flag
        int[][] temp=new int[9][9];                                             //temporary array for backtracking
        temp=board;
        for(i=0;i<9;i++)                                                        //check if any empty space available
            for(j=0;j<9;j++){
                if(board[i][j]==0){
                    empty=0;
                    break;
                }
            }
        if(empty==1)return board;
        for(i=0;i<9;i++)
            outerLoop:
            for(j=0;j<9;j++){
                if(board[i][j]>0)continue;
                for(val=1;val<10;val++){                                        //try values
                    for(k=0;k<9;k++){
                        if(board[i][k]==val)break;                              //check row consistancy 
                        if(board[k][j]==val)break;                              //check column consistancy     
                    }
                    for(k=(i/3)*3;k<(i/3+1)*3;k++)                              //check latin square consistancy
                        for(l=(j/3)*3;l<((j/3+1)*3);l++)
                            if(board[k][l]==val)break;                      
                    temp[i][j]=val;                                             //put consistant value
                    Solve(temp);                                                //recursive call for backtrack
                }
        }
        return null;                                                            
    }


    public static void main(String[] args) {
        // TODO code application logic here
        int[][] board={ {5,3,0,0,7,0,0,0,0},
                        {6,0,0,1,9,5,0,0,0},
                        {0,9,8,0,0,0,0,6,0},
                        {8,0,0,0,6,0,0,0,3},
                        {4,0,0,8,0,3,0,0,1},
                        {7,0,0,0,2,0,0,0,6},
                        {0,6,0,0,0,0,2,8,0},
                        {0,0,0,4,1,9,0,0,5},
                        {0,0,0,0,8,0,0,7,9}};
        Sudoku s=new Sudoku(board);
        int[][] temp=new int[9][9];
        temp=s.Solve(board);
        for(int i=0;i<9;i++){
            System.out.println("");
            for(int j=0;j<9;j++){
                System.out.print(temp[i][j]);
                System.out.print(",");
            }
        }
    }    
}

由于netbeans建议,我把null return语句,但它应该永远不会返回null。我找不到错误。在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

我将专注于您的Solve(int[][])方法:

public int[][] Solve(int[][] board){

在Java命名约定下,方法应该是camelCase:solve(int[][] board)

    int i, j, k,l,val;

除非必要,否则不应在方法的开头定义迭代器。它给了他们一种错误的目的感,使代码难以解释。

    int empty=1;

这应该是一个布尔值,因为它只保留1或0的值。布尔值在这里可读性更高:boolean empty = false;

    int[][] temp=new int[9][9];                                             
    temp=board;

另外,我建议将您的代码分解为&#39;段落或相关操作。当您从定义转移到某些初始逻辑时,这将是新段落的一个好位置。

    for(i=0;i<9;i++)                                                        
        for(j=0;j<9;j++){
            if(board[i][j]==0){
                empty=true;
                break;
            }
        }
    if(!empty)return board;

这应该是它自己的段落,因为它处理单个任务,检查电路板是否已解决。我还更新了它,以显示布尔人如何更好地阅读。

    for(i=0;i<9;i++)
        outerLoop:
        for(j=0;j<9;j++){
            if(board[i][j]>0)continue;
            for(val=1;val<10;val++){                                        
                for(k=0;k<9;k++){
                    if(board[i][k]==val)break;                               
                    if(board[k][j]==val)break;                                  
                }
                for(k=(i/3)*3;k<(i/3+1)*3;k++)                              
                    for(l=(j/3)*3;l<((j/3+1)*3);l++)
                        if(board[k][l]==val)break;                      
                temp[i][j]=val;                                             
                Solve(temp);                                                
            }
    }
    return null;                                                            
}

您的代码有两个返回语句,一个用于完成的板,另一个用于捕获逻辑错误。错误在您的递归调用中。只需拨打Solve(temp);,就不会保留您对数据所做的任何更改。只有在使用递归调用生成的新信息时,递归函数才有效。因此,要修复错误,请返回递归调用:

return Solve(temp);