数独求解器问题(回溯算法)无休止地运行

时间:2016-02-07 17:27:42

标签: java sudoku

我是Java的新手。这是我试图制作数独求解器的尝试。截至目前,这还没有GUI,输入您必须修改代码本身的问题。通常程序在大约30毫秒内完成数独(从一些填充值开始),如果必须从头开始(从空白数据开始),则大约100毫秒。我遇到的问题是,有时程序在没有提供解决方案的情况下继续运行,我必须手动停止它。是因为数独只有一个或几个解决方案?还是因为它被卡住了某种循环。我还注意到,如果程序中填写了最远的最右边(8,8),甚至不会尝试解决数独。也许是因为我编写代码的方式,它认为数独已经解决了。我可以让它检查最后一个未填充点而不是固定位置吗?

package sudoku;

public class Sudoku {

    static int userGrid[][]=new int[][]
            {{0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0},
             {0,0,0,0,0,0,0,0,0}};//[Horizontal][Vertical]
    static int grid[][]=new int[9][9];//Program experiments

public static void main(String[] args) {
    for(int i=0;i<9;i+=1) {
        for (int j=0;j<9;j+=1) {
            grid[i][j]=userGrid[i][j];
        }
    }
    print(grid);
    double timeStart=System.currentTimeMillis();
    print(loop(0, 0, grid));
    double timeEnd=System.currentTimeMillis();
    System.out.println("That took "+(timeEnd - timeStart)+" milliseconds to complete");
}
public static int[][] loop(int y, int x, int[][] grid) {
    while(!validity(8, 8, grid) || grid[8][8]==0)//while it's not solved
        {
            if(userGrid[y][x]!=0){

                int yy,xx;
                if (x==8) {yy=y+1;xx=0;} else {yy=y; xx=x+1;}
                loop(yy, xx, grid);

            } else {
            if(grid[y][x]<9) {//going forward

               grid[y][x]+=1;
               if(validity(y, x, grid)) {
                   int yy,xx;
                   if (x==8) {yy=y+1;xx=0;} else {yy=y; xx=x+1;}
                   loop(yy, xx, grid);
               }
            } else {
                grid[y][x]=0;
                break;}
        }
    }
    return grid;
}
public static boolean validity(int x, int y, int[][] grid) {
    String temp="";
    for(int i=0;i<9;i+=1) {
        temp+=Integer.toString (grid[i][y]);//horizontal
        temp+=Integer.toString (grid[x][i]);//vertical
        temp+=Integer.toString (grid[(x/3)*3+i/3][(y/3)*3+i%3]);//square 
    }
    int count=0, idx=0;
    while((idx=temp.indexOf(Integer.toString (grid[x][y]),idx))!=-1)
    {idx+=1;count+=1;}
    return count==3;
}

public static void print(int[][] grid) {
    System.out.println();
    for(int i=0;i<9;i+=1) {
        for (int j=0;j<9;j+=1) {
            System.out.print(grid[i][j]);
        }
        System.out.println();
    }
}
}

编辑:我调试了代码并发现了问题

通过查找最后一个未填充的数字而不是最右下方的数字(8,8)来解决故障

我遇到的另一个问题是,它不会在预先存在的数字后面回溯并且会陷入无限循环。这就是它无休止地运行的原因。

固定代码:

package sudoku;

public class Sudoku {

    static int userGrid[][]=new int[][]
            {{2,0,0,4,0,0,0,0,0},
             {0,0,4,0,9,0,0,0,0},
             {0,0,0,0,6,0,8,7,0},
             {7,0,2,0,0,0,0,8,0},
             {0,0,0,7,0,0,0,0,9},
             {0,4,9,0,0,2,0,0,5},
             {0,8,0,0,0,7,1,9,3},
             {0,5,0,0,0,4,0,0,0},
             {0,0,0,8,0,0,0,0,0}};//[Horizontal][Vertical]
    static int grid[][]=new int[9][9];//Program experiments

    //static String pGrid[][]=new String[9][9];//Possibilities

public static void main(String[] args) {
    for(int i=0;i<9;i+=1) {
        for (int j=0;j<9;j+=1) {
            grid[i][j]=userGrid[i][j];
        }
    }
    print(grid);
    double timeStart=System.currentTimeMillis();

    int lastPos = findLastCell();
    if (lastPos == 0){
        return;
    }
    int lastY = lastPos % 16;
    int lastX = lastPos / 16;

    print(loop(0, 0, lastY, lastX, grid));
    double timeEnd=System.currentTimeMillis();
    System.out.println("That took "+(timeEnd - timeStart)+"            milliseconds to complete");


}

public static int findLastCell(){
    for (int i=8; i>=0; i--){
        for (int j=8; j>=0; j--){
            if (userGrid[i][j]==0){
                return ((j * 16) + i);
            }
        }
    }
    return 0;
}

public static int[][] loop(int y, int x, int lastY, int lastX, int[][] grid) {
    while(!validity(lastY, lastX, grid) || grid[lastY][lastX]==0)//while it's not solved
        {
            while (userGrid[y][x]!=0){
                if (x==8)
                {
                    // System.out.println("Here 2");
                    y=y+1;
                    x=0;
                }
                else
                {
                    x=x+1;
                }  
            }
            if(grid[y][x]<9) {//going forward

               grid[y][x]+=1;
               if(validity(y, x, grid)) {
                   int yy,xx;
                   if (x==8)
                   {
                       //System.out.println("Here");
                       yy=y+1;
                       xx=0;
                   }
                   else
                   {
                       yy=y;
                       xx=x+1;
                   }
                   loop(yy, xx, lastY, lastX, grid);
               }
            } else {
                grid[y][x]=0;
                break;}
        }
    return grid;
}

public static boolean validity(int x, int y, int[][] grid) {
    String temp="";
    for(int i=0;i<9;i+=1) {
        temp+=Integer.toString (grid[i][y]);//horizontal
        temp+=Integer.toString (grid[x][i]);//vertical
    }
    for (int i=0; i<3; i++){
        for (int j=0; j<3; j++){
        temp+=Integer.toString (grid[(x/3)*3+i][(y/3)*3+j]);
        //square (Java doesn't round the divided no.s if they
        //are fractions. It jjust outputs them as 0
        }
    }

    int count=0, idx=0;
    while((idx=temp.indexOf(Integer.toString (grid[x][y]),idx))!=-1)
    {idx+=1;count+=1;}

    return count==3;
}

public static void print(int[][] grid) {
    System.out.println();
    for(int i=0;i<9;i+=1) {
        for (int j=0;j<9;j+=1) {
            System.out.print(grid[i][j]);
        }
        System.out.println();
    }
}
}
然而,我会补充说,我收到的答案不太有帮助。

0 个答案:

没有答案