Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过回溯解决数独问题(java) publicstaticint[]solve(int[]input){ 对于(int i=0;i_Java_Recursion_Backtracking - Fatal编程技术网

通过回溯解决数独问题(java) publicstaticint[]solve(int[]input){ 对于(int i=0;i

通过回溯解决数独问题(java) publicstaticint[]solve(int[]input){ 对于(int i=0;i,java,recursion,backtracking,Java,Recursion,Backtracking,我以前实现过一次数独解算器。它比你现在的要复杂一些,但一眨眼就解决了游戏。:) 你试图做的是用“暴力”和(尾巴)解数独递归。这意味着您正试图通过迭代所有981可能的组合来求解电路板。9到81的幂是…这是一个很大的数字。因此,您的方法将花费永恒的时间,但您将很快从尾部递归中耗尽堆栈空间 当我实现Sudoko时,它更直接。它保留了一个9x9“items”数组,其中每个items都是正方形中的值,还有一个9个布尔值的数组,表示候选对象(true==可行,false==消除)。然后它只做了一个非递归的求

我以前实现过一次数独解算器。它比你现在的要复杂一些,但一眨眼就解决了游戏。:)

你试图做的是用“暴力”和(尾巴)解数独递归。这意味着您正试图通过迭代所有981可能的组合来求解电路板。9到81的幂是…这是一个很大的数字。因此,您的方法将花费永恒的时间,但您将很快从尾部递归中耗尽堆栈空间

当我实现Sudoko时,它更直接。它保留了一个9x9“items”数组,其中每个items都是正方形中的值,还有一个9个布尔值的数组,表示候选对象(true==可行,false==消除)。然后它只做了一个非递归的求解电路板的循环


主循环将从查找只剩下1个候选方的简单过程开始。然后下一步将根据已分配的值进行简单的候选方消除。然后它将进入更复杂的消除技术,如。

最终
validNumber()
方法将不会返回任何数字,因为没有剩余的可能性,这意味着前面的一个选择是错误的。只要想象一下,该算法是从空网格开始的(显然,这个谜题是可解的1)

解决方案是保留可能的选择树,如果某些选择不正确,则只需将它们从树中删除,然后使用下一个可用的选择(或者,如果此分支中没有选择,请后退到树的更高级别)。此方法应能找到解决方案(如果有的话)。(实际上,这就是我不久前实现数独解算器的方式。)


1我想有3种不同的数独游戏:

  • “真正”正确的数独游戏,有一个唯一的完整解决方案

  • 具有多个不同完整解决方案的模糊数独,例如,一个只有7个不同数字的谜题,因此它至少有两个不同的解决方案,通过交换第8和第9个数字而有所不同

  • 不正确的数独游戏,没有完整的解决方案,例如,一行出现两次或两次以上相同的数字

  • 根据此定义,解算器算法应:

  • 证明没有解决办法

  • 返回满足初始网格的完整解决方案


  • 在“真”数独游戏中,结果是“真”根据定义的解决方案。对于模糊数独,结果可能会因算法而异。空网格是模糊数独的最终示例。

    您的算法实际上不会回溯。如果可以,它会向前移动,但当它意识到自己被困在角落时,它不会向后移动。这是因为它永远不会回溯在堆栈中重新设置任何知识,它永远不会重置方块。除非你运气好,否则你的代码将使游戏板进入转弯状态,然后打印出该转弯状态。要回溯,你需要将你设置的最后一个方块(使你转弯的方块)重置为零,这样你的算法就会知道继续尝试其他事情

    为了理解回溯,我强烈推荐一本史蒂文·斯基纳的《算法设计手册》。我在准备SWE采访时读过这本书,它确实提高了我对回溯、复杂性和图形搜索的知识。这本书的后半部分是75个经典算法问题的目录,数独是其中之一m!他有一个有趣的优化分析,你可以对搜索树进行修剪,并解决非常困难的难题。下面是我很久以前在阅读本章后编写的一些代码(按照我目前的标准,质量可能不太高,但它是有效的).我只是很快地读了一遍,并在
    solve
    方法中添加了
    solveSmart
    布尔值,它允许您打开或关闭其中一个优化,这在解决“硬”类数独板(一开始只填充了17个方块)时节省了大量时间

    公共级数独{
    静态类RowCol{
    int行;
    int col;
    RowCol(整数r,整数c){
    row=r;
    col=c;
    }
    }
    静态int numSquaresFilled;
    静态整数[][]板=新整数[9][9];
    静态无效打印板(){
    对于(int i=0;i<9;i++){
    对于(int j=0;j<9;j++){
    系统输出打印(“+(板[i][j]==0?”:板[i][j])+”;
    如果(j%3==2&&j<8)
    系统输出打印(“|”);
    }
    System.out.println();
    如果(i%3==2&&i<8)
    System.out.println(“-----------|-----------------|-----------------”;
    }
    System.out.println();
    }
    静态布尔值isEntireBoardValid(){
    对于(int i=0;i<9;i++){
    对于(int j=0;j<9;j++){
    如果(!isBoardValid(i,j)){
    返回false;
    }
    }
    }
    返回true;
    }
    静态布尔值isRowValid(int行){
    int[]计数=新的int[9];
    for(int col=0;col<9;col++){
    int n=线路板[行][col]-1;
    如果(n==-1)
    继续;
    计数[n]++;
    如果(计数[n]>1)
    返回false;
    }
    返回true;
    }
    静态布尔值isColValid(整数列){
    int[]计数=新的int[9];
    对于(int行=0;行<9;行++){
    int n=线路板[行][col]-1;
    如果(n==-1)
    继续;
    计数[n]++;
    如果(计数[n]>1)
    返回false;
    }
    返回true;
    }
    静态布尔值isSquareValid(int行,int列){
    int r=(第3行)*3;
    int c=(col/3)*3;
    int[]计数=新的int[9];
    对于(int i=0;i<3;i++){
    对于(int j=0;j<3;j++){
    int n=电路板[r+i][c+j]-1;
    如果(n==-1)
    继续;
    计数[n]++;
    
    public static int[][] solve(int[][] input){
    
            for (int i = 0; i < 9*9; i++){
                if(input[i / 9][i % 9] != 0){
                    continue;
                }
                for (int j = 1; j <= 9; j++){
                        if(validNumber(input, i / 9, i % 9, j)){
                            input[i / 9][i % 9] = j;
                            solve(input);
                        }
                }
            }
            return input;
        }
    
    public class Sudoku {
    
      static class RowCol {
        int row;
        int col;
    
        RowCol(int r, int c) {
          row = r;
          col = c;
        }
      }
    
      static int numSquaresFilled;
      static int[][] board = new int[9][9];
    
      static void printBoard() {
        for (int i = 0; i < 9; i++) {
          for (int j = 0; j < 9; j++) {
            System.out.print(" " + (board[i][j] == 0 ? " " : board[i][j]) + " ");
            if (j % 3 == 2 && j < 8)
              System.out.print("|");
          }
          System.out.println();
          if (i % 3 == 2 && i < 8)
            System.out.println("---------|---------|---------");
        }
        System.out.println();
      }
    
      static boolean isEntireBoardValid() {
        for (int i = 0; i < 9; i++) {
          for (int j = 0; j < 9; j++) {
            if (!isBoardValid(i, j)) {
              return false;
            }
          }
        }
        return true;
      }
    
      static boolean isRowValid(int row) {
        int[] count = new int[9];
        for (int col = 0; col < 9; col++) {
          int n = board[row][col] - 1;
          if (n == -1)
            continue;
          count[n]++;
          if (count[n] > 1)
            return false;
        }
        return true;
      }
    
      static boolean isColValid(int col) {
        int[] count = new int[9];
        for (int row = 0; row < 9; row++) {
          int n = board[row][col] - 1;
          if (n == -1)
            continue;
          count[n]++;
          if (count[n] > 1)
            return false;
        }
        return true;
      }
    
      static boolean isSquareValid(int row, int col) {
        int r = (row / 3) * 3;
        int c = (col / 3) * 3;
        int[] count = new int[9];
        for (int i = 0; i < 3; i++) {
          for (int j = 0; j < 3; j++) {
            int n = board[r + i][c + j] - 1;
            if (n == -1)
              continue;
            count[n]++;
            if (count[n] > 1)
              return false;
          }
        }
        return true;
      }
    
      static boolean isBoardValid(int row, int col) {
        return (isRowValid(row) && isColValid(col) && isSquareValid(row, col));
      }
    
      static RowCol getOpenSpaceFirstFound() {
        for (int i = 0; i < 9; i++) {
          for (int j = 0; j < 9; j++) {
            if (board[i][j] == 0) {
              return new RowCol(i, j);
            }
          }
        }
        return new RowCol(0, 0);
      }
    
      static RowCol getOpenSpaceMostConstrained() {
        int r = 0, c = 0, max = 0;
        int[] rowCounts = new int[9];
        int[] colCounts = new int[9];
        for (int i = 0; i < 9; i++) {
          for (int j = 0; j < 9; j++) {
            if (board[i][j] != 0)
              rowCounts[i]++;
            if (board[j][i] != 0)
              colCounts[i]++;
          }
        }
    
        int[][] squareCounts = new int[3][3];
        for (int i = 0; i < 3; i++) {
          for (int j = 0; j < 3; j++) {
            int count = 0;
            for (int m = 0; m < 3; m++) {
              for (int n = 0; n < 3; n++) {
                if (board[(i * 3) + m][(j * 3) + n] != 0)
                  count++;
              }
            }
            squareCounts[i][j] = count;
          }
        }
    
        for (int i = 0; i < 9; i++) {
          for (int j = 0; j < 9; j++) {
            if (board[i][j] == 0) {
              if (rowCounts[i] > max) {
                max = rowCounts[i];
                r = i;
                c = j;
              }
              if (colCounts[j] > max) {
                max = rowCounts[j];
                r = i;
                c = j;
              }
            }
          }
        }
        return new RowCol(r, c);
      }
    
      static boolean solve() {
        if (81 == numSquaresFilled) {
          return true;
        }
    
        boolean solveSmart = true;
        RowCol rc = solveSmart ? getOpenSpaceMostConstrained() : getOpenSpaceFirstFound();
        int r = rc.row;
        int c = rc.col;
        for (int i = 1; i <= 9; i++) {
          numSquaresFilled++;
          board[r][c] = i;
          if (isBoardValid(r, c)) {
            if (solve()) {
              return true;
            }
          }
          board[r][c] = 0;
          numSquaresFilled--;
        }
        return false;
      }
    
      public static void main(String[] args) {
    
        // initialize board to a HARD puzzle
        board[0][7] = 1;
        board[0][8] = 2;
        board[1][4] = 3;
        board[1][5] = 5;
        board[2][3] = 6;
        board[2][7] = 7;
        board[3][0] = 7;
        board[3][6] = 3;
        board[4][3] = 4;
        board[4][6] = 8;
        board[5][0] = 1;
        board[6][3] = 1;
        board[6][4] = 2;
        board[7][1] = 8;
        board[7][7] = 4;
        board[8][1] = 5;
        board[8][6] = 6;
        numSquaresFilled = 17;
    
        printBoard();
        long start = System.currentTimeMillis();
        solve();
        long end = System.currentTimeMillis();
        System.out.println("Solving took " + (end - start) + "ms.\n");
        printBoard();
      }
    }