web-dev-qa-db-ja.com

ソリューションカウンターによる数独バックトラック

背景

次のような数独ソルバーアルゴリズム(バックトラッキング)を実装しました。

//Backtracking-Algorithm
public static boolean solver(int[][] board) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (board[i][j] == 0) {
                for (int n = 1; n < 10; n++) {
                    if (checkRow(board, i, n) && checkColumn(board, j, n) && checkBox(board, i, j, n)) {
                        board[i][j] = n;
                        if (!solver(board)) {
                            board[i][j] = 0;
                        } else {
                            return true;
                        }
                    }
                }
                return false;
            }
        }
    }
    return true;
}

このソリューションは正常に機能しています(数独を解決できます)。

私が達成しようとしていること

解決策が1つしかないか、それとも複数あるか、アルゴリズムが教えてくれることを実現したいと思います。

私が試したこと

私は、戻り値の型をintに変更して可能な解決策を数えることで目標を達成しようとしました(2つで終了するので、2つの解決策がある場合は、「複数の」解決策があると言えます。したがって、基本的には、解決策がないか、1つまたは多くの解決策があるかを知りたいだけです。

// Backtracking-Algorithm
public int solver(int[][] board, int count) { //Starts with count = 0
  if (count < 2) {
    for (int i = 0; i < GRID_SIZE; i++) {
      for (int j = 0; j < GRID_SIZE; j++) {
        /*
         * Only empty fields will be changed
         */
        if (board[i][j] == EMPTY) {
          /*
           * Try all numbers between 1 and 9
           */
          for (int n = 1; n <= GRID_SIZE; n++) {
            /*
             * Is number n safe?
             */
            if (checkRow(board, i, n) && checkColumn(board, j, n) && checkBox(board, i, j, n)) {
              board[i][j] = n;
              if (solver(board, count) > count) {
                count++;
              } else {
                board[i][j] = 0;
              }
            }
          }
          return count;
        }
      }
    }
    return count + 1;
  }
  return count;
}

問題は、countが常に「1」になり、アルゴリズムが停止することです。

質問

コードを機能させるには、コードにどのような変更が必要ですか?

4
Philipp Wilhelm

Aziz Sonawallaによる this 回答のおかげで、私はそれを理解したと思います。

次の実装は、一意に解決可能な数独 here を解決することができました。また、アルゴリズムは複数の解( example )で数独を解くことができ、複数の解があることを認識できます。この場合、プログラムは可能な解決策の1つのみを提供します。

コードは次のようになります。

// Backtracking-Algorithm
public int[][] board2 = new int[GRID_SIZE][GRID_SIZE];

public int solver(int[][] board, int count) { // Starts with count = 0

    for (int i = 0; i < GRID_SIZE; i++) { //GRID_SIZE = 9

      for (int j = 0; j < GRID_SIZE; j++) {

        /*
         * Only empty fields will be changed
         */

        if (board[i][j] == EMPTY) { //EMPTY = 0

          /*
           * Try all numbers between 1 and 9
           */

          for (int n = 1; n <= GRID_SIZE && count < 2; n++) {

            /*
             * Is number n safe?
             */
            if (checkRow(board, i, n) && checkColumn(board, j, n) && checkBox(board, i, j, n)) {

              board[i][j] = n;
              int cache = solver(board, count);
              if (cache > count) {
                count = cache;
                for (int k = 0; k < board.length; k++) {
                  for (int l = 0; l < board.length; l++) {
                    if (board[k][l] != EMPTY) {
                      board2[k][l] = board[k][l];
                    }

                  }
                }

                board[i][j] = EMPTY;

              } else {
                board[i][j] = EMPTY;
              }

            }
          }
          return count;
        }
      }
    }
    return count + 1;
}

ソリューションは配列board2に保存されました。

この実装は意図したとおりに機能しています(私の知る限り)。間違いを見つけた場合はコメントを残してください。

0
Philipp Wilhelm