0

数独バックトラッキングソルバーを書いていますが、行き詰まっていて、理由がわかりません。私の再帰呼び出しは大丈夫だと思います。私が欠けているものは何ですか?

入力は、1行のグリッド初期レイアウトでinput.txtファイルから読み取られます。

input.txt:

004020000201950070090004852005490001006000900800051300958100020010072608000080500

編集:グリッドの解決を完了していないとして「スタック」を意味します

これはサンプル出力です:

current move count is 6
3 6 4 7 2 8 1 9 0 
2 0 1 9 5 0 0 7 0 
0 9 0 0 0 4 8 5 2 
0 0 5 4 9 0 0 0 1 
0 0 6 0 0 0 9 0 0 
8 0 0 0 5 1 3 0 0 
9 5 8 1 0 0 0 2 0 
0 1 0 0 7 2 6 0 8 
0 0 0 0 8 0 5 0 0 

プログラム:

package sudoku;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;




public class Main {

 static boolean checkRow( int row, int num, int grid[][])
   {
      for( int col = 0; col < 9; col++ )
         if( grid[row][col] == num )
            return false ;

      return true ;
   }

static boolean checkCol( int col, int num, int grid[][] )
   {
      for( int row = 0; row < 9; row++ )
         if( grid [row][col] == num )
            return false ;

      return true ;
   }


static boolean checkBox( int row, int col, int num, int grid[][] )
   {
      row = (row / 3) * 3 ;
      col = (col / 3) * 3 ;

      for( int r = 0; r < 3; r++ ){
         for( int c = 0; c < 3; c++ ){
            if( grid[row+r][col+c] == num )
            return false ;          
         }
      }
      return true ;
   }


  static void printSolvedGrid(int grid[][]){

       for (int i=0; i<grid.length; i++){
            for (int j=0; j<grid.length;j++){
              System.out.print(grid[i][j]+" ");
            } System.out.println();
        }

  }


   static int moveCounter=0;

   static boolean solve(int row, int col, int [][]grid){

       if (row>=grid.length){

           System.out.println("solution found");
           printSolvedGrid(grid);

       }

       if( grid[row][col] != 0 ){
            next( row, col, grid ) ;
       }

       else {
         // Find a valid number for the empty cell
         for( int num = 1; num < 10; num++ )
         {
            if( checkRow(row,num,grid) && checkCol(col,num,grid) && checkBox(row,col,num,grid) )
            {
               grid[row][col] = num ;
               moveCounter++;
               System.out.println("current move count is " + moveCounter);
               printSolvedGrid(grid);
               next( row, col, grid );
               return true;
            }
         }

       }
       return false;
    }


  public static void next( int row, int col, int [][] grid )
   {
      if( col < 8 ) //pass to next col
         solve( row, col + 1, grid ) ;
      else //pass to next row 
         solve( row + 1, 0, grid ) ;
   }







    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new FileReader(new File("input.txt")));
        char gridChar[] = br.readLine().toCharArray();

       int [][] grid = new int [9][9];

        int gridCharIndex=0;
        for (int i=0; i<grid.length; i++){
            for (int j=0; j<grid.length;j++){

              grid[i][j]= Integer.parseInt(gridChar[gridCharIndex++]+"");
              System.out.print(grid[i][j]+" ");
            } System.out.println();
        }

        solve(0,0, grid);
        }//end method main
    }//end class Main
4

4 に答える 4

5

solveバックトラックが発生しない理由の重要なヒントは、戻り値がまったく使用されていないというブール関数が呼び出されていることです。

このループでは:

     for( int num = 1; num < 10; num++ )
     {
        if( checkRow(row,num,grid) && checkCol(col,num,grid) && checkBox(row,col,num,grid) )
        {
           grid[row][col] = num ;
           moveCounter++;
           System.out.println("current move count is " + moveCounter);
           printSolvedGrid(grid);
           next( row, col, grid );
           return true;
        }
     }

現在のセルに適した候補を見つけ、プラグを差し込んでからを呼び出しますnextnext次にを呼び出しますsolveが、戻った後は、それが正しい選択であると想定します。return true; したがって、solvefalseが返された場合は、それに注意を払わず、そのセルの他の選択を試みていません。

于 2011-06-21T23:06:31.690 に答える
3

再帰を使用している間(コードを最適化するのは非常に簡単ではありませんが、スタックが構築されないように末尾再帰にすることができますが、そうではありません。これは別の問題です)、実際には解決策が行き詰まっています。可能な各ブランチをチェックします。

コードがスタックするシナリオの例を示します。

これを数独パズルの左上隅と考えてください。

0 0 3
4 5 6
7 8 9
0 2

アルゴリズムは正方形[0][0]をチェックし、1が適切であると判断します。次に、正方形[0] [1]のチェックに進み、1が不適切であることがわかります。したがって、2をチェックすると、その列にすでに2があることがわかります。そして残りの数字は箱の中にあります。そのため、前の決定に戻ることは決してないので、行き詰まります。

それは何をすべきですか?それは再発するはずです、それはこのシナリオにつながった決定を後退させて変えることができるはずです。「真の」再帰(つまり、有効な再帰ツリーのすべての可能なオプションをチェックするもの)は、最後の決定を「元に戻し」、次の決定を試すことができます。つまり、2が左上隅にあることを見つけて、続行します。の上。

于 2011-06-21T22:50:53.090 に答える
1

修理済み:

ブール値とreturnステートメントを削除しました:)

ところで、私の元のテストケースには解決策がないようですが、これら2つの入力は1つになります。

input1.txt

900576813630090002005000900001004730200000008076900500003000600400050091712869005 

input2.txt(これは難しいです)

200609050604083000000700000048000200000010000001000490000001000000970103020408005 

コード:

static void solve(int row, int col, int [][]grid){

       if (row>=grid.length){

           System.out.println("solution found");
           printSolvedGrid(grid);
           System.exit(0);

       }

       if( grid[row][col] != 0 ){
            next( row, col, grid ) ;
       }

       else {
         // Find a valid number for the empty cell
         for( int num = 1; num < 10; num++ )
         {
            if( checkRow(row,num,grid) && checkCol(col,num,grid) && checkBox(row,col,num,grid) )
            {
               grid[row][col] = num ;
               moveCounter++;
               System.out.println("current move count is " + moveCounter);
               printSolvedGrid(grid);
               next( row, col, grid );

            }
         }

         grid[row][col] = 0 ;
       }

    }
于 2011-06-21T23:46:26.667 に答える
0

「スタック」が何を意味するのか正確にはわかりません。コードがスタックしているのか、パズルを解けないだけなのか。

簡単に見てみると、コードに問題はありませんが、同時に、再帰の使用方法は実際には正しくありませんが、解決策が見つからなくても実行されるはずです...

しかし、あなたが使用していない数独パズルを解くための他のテクニックがあります、X-Wingは最も洗練されたものの1つかもしれません...

あなたが今していることに続いても、おそらくそれらのテストを数回実行する必要があるでしょう...

編集

私はあなたのコードを実行し、うまく実行しました、最後の段階で、それは印刷されました:

current move count is 6
3 6 4 7 2 8 1 9 0 
2 0 1 9 5 0 0 7 0 
0 9 0 0 0 4 8 5 2 
0 0 5 4 9 0 0 0 1 
0 0 6 0 0 0 9 0 0 
8 0 0 0 5 1 3 0 0 
9 5 8 1 0 0 0 2 0 
0 1 0 0 7 2 6 0 8 
0 0 0 0 8 0 5 0 0 

そしてそれは行われました...それはもう何も解決しません。

使う代わりに

row>=grid.length

終了条件として、グリッドを調べて「0」が残っているかどうかを確認する必要があります。そしてその場合row>=grid.length、あなたは再び始めるべきです:solve(0,0,grid)。それでもすべてを解決できるわけではありませんが、間違いなくもう少し先に進みます。

于 2011-06-21T22:38:16.607 に答える