数独算法回溯实现 - Java

5

我有一个大学作业要解决数独……我读了一些有关算法X和Dancing算法的资料,但它们对我没有帮助。

我需要使用回溯法来解决问题。我已经在二维数组中硬编码了一些索引,这些索引来自维基百科上给出的数字位置(因此我确定这是可解的)。

我得到的代码如下:

public void solveSudoku(int row, int col)
   {
      // clears the temporary storage array that is use to check if there are
      // dublicates on the row/col
      for (int k = 0; k < 9; k++)
      {
         dublicates[k] = 0;
      }
      // checks if the index is free and changes the input number by looping
      // until suitable
      if (available(row, col))
      {
         for (int i = 1; i < 10; i++)
         {
            if (checkIfDublicates(i) == true)
            {
               board[row][col] = i;
               if (row == 8)
                  solveSudoku(0, col + 1);
               else if (col == 8)
                  solveSudoku(row + 1, 0);
               else
                  solveSudoku(row, col + 1);

               board[row][col] = 0;
            }
         }
      }
      // goes to the next row/col
      else
      {
         if (row == 8)
            solveSudoku(0, col + 1);
         else if (col == 8)
            solveSudoku(row + 1, 0);
         else
            solveSudoku(row, col + 1);
      }
   }

   /**
    * Checks if the spot on the certain row-col index is free of element
    * 
    * @param row
    * @param col
    * @return
    */
   private boolean available(int row, int col)
   {
      if (board[row][col] != 0)
         return false;
      else
         return true;
   }

   /**
    * Checks if the number given is not already used in this row/col
    * 
    * @param numberToCheck
    * @return
    */
   private boolean checkIfDublicates(int numberToCheck)
   {
      boolean temp = true;
      for (int i = 0; i < dublicates.length; i++)
      {
         if (numberToCheck == dublicates[i])
         {
            temp = false;
            return false;
         }
         else if (dublicates[i] == 0)
         {
            dublicates[i] = numberToCheck;
            temp = true;
            return true;
         }
      }
      return temp;
   }

我在以下代码中遇到了StackOverflow错误:
// goes to the next row/col
          else
          {
             if (row == 8)
                solveSudoku(0, col + 1);
             else if (col == 8)
                solveSudoku(row + 1, 0);
             else
                solveSudoku(row, col + 1);
          }

这意味着我必须在某个时刻停止递归,但我无法弄清楚如何停止!如果您发现solve()函数中的任何其他错误,请让我知道。因为我不确定我完全理解“回溯”...


http://www.byteauthor.com/2010/08/sudoku-solver/ 这个网站有一个很好的例子。 - chAmi
维基百科 ;) - sp00m
你应该检查一下你的重复代码。我不明白这个怎么能够检查一个数字是否被允许。每次调用SolveSudoku时,你总是重置它,所以它会忘记所有东西。我也对一个由9个元素组成的数组如何检查所有内容表示怀疑。 - Origin
4个回答

3
你可以停止递归,例如如果你追踪当前递归深度。
public void solveSudoku(int row, int col, int recursionDepth) {
    // get out of here if too much
    if (recursionDepth > 15) return;

    // regular code...
    // at some point call self with increased depth
    solveSudoku(0, col + 1, recursionDepth + 1);
}

如果你在solve()函数中发现其他错误,请告诉我。

代码太多了 :)


3
这大致是我过去处理此类问题的方式。
Whenever all the definite moves have been taken and there is a choice of equally good next moves:
    copy your grid data structure and push it onto a stack.
    take the first candidate move and continue solving recursively
    Whereever you get stuck:
         pop the saved grid off the stack
         take the next candidate move.

1

我用更简单的方式实现了它:

public void solve(int row, int col)
   {
      if (row > 8)
      {
         printBoard();
         System.out.println();
         return;
      }
      if (board[row][col] != 0)
      {
         if (col < 8)
            solve(row, col + 1);
         else
            solve(row + 1, 0);
      }
      else
      {
         for (int i = 0; i < 10; i++)
            if (checkRow(row, i) && checkCol(col, i))
                  //&& checkSquare(row, col, i))
            {
               board[row][col] = i;
               if (col < 8)
                  solve(row, col + 1);
               else
                  solve(row + 1, 0);
            }
         board[row][col] = 0;
      }
   }

   private boolean checkRow(int row, int numberToCheck)
   {
      for (int i = 0; i < 9; i++)
         if (board[row][i] == numberToCheck)
            return false;

      return true;
   }

   private boolean checkCol(int col, int numberToCheck)
   {
      for (int i = 0; i < 9; i++)
         if (board[i][col] == numberToCheck)
            return false;

      return true;
   }

1

我不确定你为什么说Dancing Links和Algorithm X没有用。
你是指你无法将数独映射到Algorithm X所设计解决的Exact Cover问题的实例中吗?
还是说这种方法对你的需求来说太复杂了?

如果是前者,你可以看一下:Java实现Knuth的Dancing Links算法的数独求解器。它非常清晰,并且也解释了背后的原理。

N.B. Algorithm X是一种回溯算法,因此,如果这是你唯一的要求,你绝对可以使用这种方法。

希望这可以帮助到你。


好的,我并没有说Dancing Links和Algorithm X没有用。我是说我无法真正理解它们,所以我无法使用它们。但是我会阅读你给我的链接中写的内容。 谢谢 ;) - Milkncookiez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接