5

学年度の最後のプロジェクト(CS学生としての最初の年)のコードでバグを見つけるのに問題があります。ナイトツアーの問題の実装で再帰に固執しています。問題のファイルは次のとおりです:https ://github.com/sheagunther/tsp161knightstour/blob/master/KnightsTourRecursiveSearch.java

具体的には、私の問題はコードのこのセクション(265行目から)にあります。

   else{
   for(int i = 0; i < numberOfPossibleNextMoves; i++){
      Cell nextCellToMoveTo = candidateNextMoves.get(i);

      int currentRowStorage = currentRow;
      int currentColumnStorage = currentColumn;
      currentRow = nextCellToMoveTo.row;
      currentColumn = nextCellToMoveTo.column;

      listOfMoves.add(nextCellToMoveTo);
      chessBoard[currentRow][currentColumn] = 1;
      currentMoveNumber++;

      boolean tourFound = findTour();

      if(tourFound){
         return true;
            }
            else{ // Undo the last move just made
               backtrackCount++;
               chessBoard[currentRow][currentColumn] = -1;
               currentRow = currentRowStorage;
               currentColumn = currentColumnStorage;                           
               listOfMoves.remove(nextCellToMoveTo);
               currentMoveNumber--;         
            }
         }
         return false;

これがfindTour()の終わりです。これは、現在の正方形(別名セル)から可能なすべての移動をテストするプログラムの一部であり、新しく移動した正方形からツアーを完了できる場合はtrueを返します。広場からツアーを完了できない場合は、else {に入り、移動を元に戻します。ここが問題だと思います。

現在、上記のようにコードを設定すると、プログラムは無限の再帰ループに閉じ込められます。

else{ステートメントのこの部分に注意してください。

chessBoard[currentRow][currentColumn] = -1;
currentRow = currentRowStorage;
currentColumn = currentColumnStorage;

コードのこの部分は、chessBoardの正方形を-1に変更します。これは、訪問されていないことを意味します(1 =訪問済み)。上記のように、新しい移動のcurrentRowとcurrentColumnを使用して、正方形を未訪問に戻します。これらの値は、currentRowStorageとcurrentColumnStorageを使用して以前のジャンプ値にリセットされます。

コードをに変更した場合

currentRow = currentRowStorage;
currentColumn = currentColumnStorage;
chessBoard[currentRow][currentColumn] = -1;

移動の最後の1/3程度が、いくつかの正方形の間を行ったり来たりしているという誤ったツアーを正常に検出します。これは、リセット手順を正しく処理しないことを考えると予想されます。

私の問題は、変数を宣言している場所が原因であると思われます。これは私の最初の複雑な再帰的な問題であり、currentRow/ColumnとcurrentRow/ColumnStorageの間の切り替えを正しく処理しているかどうかはわかりません。私はそれらを多かれ少なかれローカルで宣言する必要がありますか?

プロジェクトを説明するページは次のとおりです。http://cs.usm.maine.edu/~briggs/webPage/c161/projects/KnightsTour.html

要件の関連セクションは次のとおりです。

ツアーが完了していない場合、findTourは、騎士の現在のセルから到達可能な空のセルの(おそらく空の)リストを判別し、このリストをローカルで宣言されたリスト変数、candidateNextMovesに格納します。このリスト変数をメソッドに対してローカルに宣言することが重要です。このリストが空の場合、現在の部分ツアーを延長する方法がないため、findTourはfalseを返す必要があります。リストが空でない場合、findTourは、次のようにリストの移動ごとにツアーを延長しようとします。リストを繰り返し処理し、リストの各セルについて、そのセルに次の移動を行い、L(ツアー内の移動のリスト)、B(ボードの状態の2D配列(訪問済み、この動きを反映するために、訪問されていない))、currRow、およびcurrCol。次に、再帰的に自分自身を呼び出します。呼び出しの結果をローカルで宣言されたブール変数に割り当てます。これには「success」という名前を付けることができます。成功にtrueが割り当てられている場合、findTourはtrueを返します。成功が偽の場合、findTourは、実行したばかりの移動、つまり「バックトラック」を元に戻し、candidateNextMovesの次の移動を試みます。0に初期化され、移動を元に戻すたびにインクリメントされる静的int変数backtrackCountを維持します。

注-ブール値を「success」ではなく「tourFound」と呼びました。

4

1 に答える 1

5

無限再帰でよくあることですが、最初にチェックする場所は、そこから抜け出す方法についての条件です。この場合、次の場合にのみ脱出できます。

if(currentMoveNumber == numberOfMovesOnBoard){
     return true;
  }

currentMoveNumber が numberOfMovesOnBoard に達するのを妨げるようなアルゴリズムと初期化を確認してください。

ヒント: 再帰メソッドに入る前の開始条件は何ですか?

于 2012-05-11T20:06:08.070 に答える