2012-03-01 8 views
3

可能性の重複:
Sudoku solver in java, using backtracking and recursion数独再帰はバックトレイン中に問題があります。 (ブルートフォース)

私は再帰とブルートフォースを使用して数独を解決するプログラムを作成しています。私の重要な問題は、どうやって止まってしまったのかを私が理解していないということです。

  1. は数独でのゼロの数を探す:

    プログラムの一般的なアルゴリズムは次のようです。

  2. 最初の0(getNextEmptyメソッドでこれを行います)の位置に数字を挿入します(insertNumberは値がスドクルールに準拠していることを確認し、そうであればtrueを返します)。

  3. 次に、再帰呼び出しを行います。ゼロがなくなると終了します(nはゼロの数です)。

  4. プログラムが停止したポイントに達すると、ピースを変更するためにバックトラックする必要があります。しかし、これはどのように可能ですか?

実際には、セルクラスは調整するセルの位置を[row、column]の形式の配列に保持します。そのセルに関連付けられた行、列、またはより小さなグリッドを返すメソッドがあります。

私は手持ちまたはすべてのコードを要求していませんが、正しい方向のちょっとした動きで十分です。再帰の理解に正当な関心があります。

public static int[][] getSolution(int[][] grid) { 
    for (int i = 0; i < 9; i++) { 
     System.arraycopy(grid[i], 0, SolveSudoku.grid[i], 0, 9); 
    }// end for 
    int n = getZeroes(); 
    return getSolution(n); 
}//end getSolution 

private static int[][] getSolution(int n) { 
    if (n == 0) { 
     return grid;   
    }//end if 
    Cell cell = getNextEmpty(); 
    boolean fits = false; 
    for (int i = 0; i <= 9; i++) { 
     fits = insertNumber(cell, i); 
     if (fits) { 
      break; 
     }else { 
      //I do not understand what I should do here 
     } 
    }//end for 
    return getSolution(n - 1); 
}//end getSolution 
+0

「ブルートフォース」? – Lion

+0

はい、それは動作するまですべての組み合わせを試すことです。スドクを解く計算されたアプローチではなく。 – Tony

+0

これが真剣な強さに半分合理的であるかどうかを調べるために、いくつかのバック・オブ・ザ・エンベロープの計算をしましたか?私は問題があまりよく分かりませんが、これは私が「難しい」パズルを取得した場合、数百年または数千年にわたり回転できるものとして私を襲います。あるいは、あなたが不可能なものを手に入れれば、ずっとずっと長くなります(あなたは間違ったパスをすべて列挙しなければなりません)。 – yshavit

答えて

2

右方向にナッジ。グリッドを解決するために必要なすべての情報を把握していないので、あなたのアプローチは少し微調整する必要があります。

private static int[][] getSolution(int n) { 
    if (n == 0) { 
     return grid;   
    }//end if 

    Cell cell = getNextEmpty(); 
    boolean fits = false; 
    for (int i = 0; i <= 9; i++) { 
     fits = insertNumber(cell, i); 
     if (fits) { 
      break; // means i fits in Cell 
     } else { 
      // i doesn't fit... try the next i 
      // don't need to do anything 
     } 
    }//end for 
    if (!fits) { 
     // There are no numbers that fit in this Cell 
     // What should happen? 
     // Did I make a bad guess? 
     // How do I BACKTRACK and correct a previous guess? 
    } 
    return getSolution(n - 1); 
}//end getSolution 
+0

私はこれらの行に沿って考えていました。私はすべての動きを記録したarraylistを作成し、それが問題に陥ったときに後退することを検討しました。しかし、私の教授からは「これは必要ではありません。あなたは1つの「動き」を作り出していると言われました。再帰的な呼び出しは他のすべての動きを作り出します。これは私を捨てているようだ。 – Tony

+0

[バックトラック](http://en.wikipedia.org/wiki/Backtracking#Pseudocode)の擬似コードを見てください。あなたはほとんど正しいアイデアを持っています。ループを適切な場所に配置するだけです。 –

+0

申し訳ありません...私はあなたが正しい場所にあなたの再帰的な呼び出しを取得する必要があると言っていた...あなたのループではない –

1

一般に、再帰的ブルートフォースでは、以下のコードに似た構文を使用します。これは、あなたが何らかの行動をした後にそれを数えることができるからです。それが新しい「出発位置」です。 だから、このようになります

private void Guess(int[][] grid) 
{ 
    if(/**grid is a solution **/) 
     //signal success 
    else 
    { 
     if(/*seed out any bad, unacceptable answers you may have missed*/) 
      return;//this includes cases when there are no more zeros 
     //for every possible move, 
     //make a modified grid, with one move done, and call 
     Guess(ModifiedGrid);//for every possible move, generally you can modify 
     //grid itself, because its passed by value 
    } 
} 
+0

バックトラックは難しいので、一般的には静的グリッドで作業しない方が良いです。ここではグリッドを値渡しにする標準的な方法を使用します。唯一の制限は、メモリ不足の可能性がありますが、理論的にはブルートフォース強制のオプションの方法です。 –

+0

残念ながら、この静的グリッドを割り当てに使用する必要があります。 – Tony

+0

あなたはマップのような何かを加えて、あなたが行ったすべての変更を含む別の静的配列を作ることができます。基本的に変更#を入力すると、あなたが行った変更の位置x、yが返されます。その変更を元に戻すことができます。このコードはもう少し長くなるでしょうが、あなたが理解してくれることを願っています。私が助けてくれたら投票してください! –