2016-03-29 5 views
3

ボード全体を占有するためにチェスボードに8つの司教を設定するプログラムを書く仕事があります。最初の解決策が見つかったら、それは終了し、すべてを印刷します。ここに私の書かれたコードはJavaであり、私はバックトラックを使ってそれを仕上げることに苦労している(その場所はコードにコメントされている)。8ボード全体を占領する司教[バックトラック]

/* 
* 0 - not occupied square 
* 1 - bishop standing square 
* 2 - occupied square (diagonal) 
*/ 
public class BishopsBT { 
public int [][] solution; 
final int N = 8; // number of squares in column and row (chess board) 
final int solved = 120; //Sum of 1's and 2's in case of all occupied board 
int sum; //current sum of board 

public BishopsBT(){ 
    solution = new int [N][N] ; 
} 

public void solve() { 
    if(placeBishops(0)){ 
     //print the result 
     clear(); // clears all 2's 
     for (int i = 0; i < N; i++) { 
      for (int j = 0; j < N; j++) { 
       System.out.print(" " + solution[i][j]); 
      } 
      System.out.println(); 
     } 
    } else{ 
     System.out.println("NO SOLUTION EXISTS"); 
    } 
} 

public boolean placeBishops (int bishop){ 

    for (int row = 0; row < N; row++) { 
     // check if bishop can be placed 
     if (canPlace(solution, row, bishop)) { 
      // place the bishop 
      solution[row][bishop] = 1; 
      } 
     } 

    if (allSpaceOccupied()) { 
     return true; 
    } else { 
     // SOME BACKTRACKING CODE HERE 
     return false; 
    } 

    } 

// check if bishop can be placed at matrix[row][column] 
public boolean canPlace(int[][] matrix, int row, int column) { 

    // we need to check all diagonals 
    // whether no bishop is standing there 

    for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) { 
     if (matrix[i][j] == 1) { 
      return false; 
     } 
    } 

    for (int i = row, j = column; i >= 0 && j < matrix.length; i--, j++) { 
     if (matrix[i][j] == 1) { 
      return false; 
     } 
    } 

    for (int i = row, j = column; i < matrix.length && j >= 0; i++, j--) { 
     if (matrix[i][j] == 1) { 
      return false; 
     } 
    } 

    for (int i = row, j = column; i < matrix.length && j < matrix.length; i++, j++) { 
     if (matrix[i][j] == 1) { 
      return false; 
     } 
    } 
    // if we are here that means we are safe to place Bishop 
    return true; 
} 

public boolean allSpaceOccupied() { 

    // clears previously occupied space 
    clear(); 

    // occupies new space 
    for (int i = 0; i < solution.length; i++) { 
     for (int j = 0; j < solution.length; j++) { 
    if (solution[i][j] == 1) diagonalOccupy(i,j); 
     } 
    } 
    sum = 0; 
    // counts sum of occupied space 
    for (int i = 0; i < solution.length; i++) { 
     for (int j = 0; j < solution.length; j++) { 
    sum += solution [i][j]; 
     } 
    } 

    if (sum == solved) return true; 
    // else 
    return false; 
} 

public void diagonalOccupy(int row, int column) { 
    // writes 2 in each bishop's occupied square 
    for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) { 
     if (solution[i][j] == 0) { 
      solution[i][j] = 2; 
     } 
    } 

    for (int i = row, j = column; i >= 0 && j < solution.length; i--, j++) { 
     if (solution[i][j] == 0) { 
      solution[i][j] = 2; 
     } 
    } 

    for (int i = row, j = column; i < solution.length && j >= 0; i++, j--) { 
     if (solution[i][j] == 0) { 
      solution[i][j] = 2; 
     } 
    } 

    for (int i = row, j = column; i < solution.length && j < solution.length; i++, j++) { 
     if (solution[i][j] == 0) { 
      solution[i][j] = 2; 
     } 
    } 

} 
// clears all 2's on the board 
public void clear() { 
    for (int i = 0; i < solution.length; i++) { 
     for (int j = 0; j < solution.length; j++) { 
      if (solution[i][j] == 2) solution[i][j] = 0; 
     } 
    } 
} 

public static void main(String[] args) { 
    BishopsBT q = new BishopsBT(); 
    q.solve(); 
} 
} 

私のプログラムは、最初の列に司教を入れて、このレイアウトはすべてのスペースを占めていないということです。もちろん、私は単にすべてを3列目に置くことができ、問題は解決されます。しかし、私はバックトラックを使用し、どのように考えている必要があります。アイデアやヒントがあれば、本当にうれしく思います。

答えて

2

解決策は、すべての司教を異なる行に配置する必要があると想定しています。これはすべてのソリューションで当てはまるわけではありません。 (すべての司教が第3列または第4列にある解決策がありますが、あなたはすべての解決策を探しているわけではありませんが、この仮定によって多くの解決策を見逃すことになります)。

あなたもcanPlaceチェックが必要です:司教たちが互いに脅かさないという制限はありません。 (これは、検索速度を上げる有効な手法かもしれませんが、適用時にはいくつかのソリューションを見逃してしまいます。使用する場合は、配置済みの司教のすべての対角セルを確認する必要はありません。

バックトラッキングでブルートフォースアプローチを使用する場合は、すべての可能なビショップの組み合わせをテストできます。これは、現在のセルが「占有」されているかどうかを確認するのに十分です。それはC(64,8)または4,426,165,368の組み合わせです。

あなたは可能性を大幅に減らすことができますが、司教が異なる行にいなければならないと仮定することではありません。代わりに、ソリューションは2つの独立したソリューションで構成されています。白い四角の司教は白い四角を脅かすだけで、黒い四角の司教は黒い四角を脅かすことができます。それで、すべての白い四角を脅かす4つの司教を取締役会に置く解決策を見いだしてください。その後

(あなたはすべてのソリューションを検索したい場合は、すべてののkサブ解決策を見つけるとK²完全なソリューションにそれらを組み合わせています。)

例この分離はにテストするための可能な配置をダウンカットC(32,8)、または35,960である。行ごとに1つのビショップがある場合にのみ構成を考慮する戦略は、8^8(約1600万)の可能性をチェックします。それはいくつかの解決策を見落とし、4つの司教が白い四角になく、4つの黒い四角に四つの司教がいない場合の魔法の構成をチェックします。

バックトラックの原則は、他の回答に記載されています。あなたはこのように32白い四角にラベルを付ける場合:

01 02 03 04 
    05 06 07 08 
09 10 11 12 
    13 14 15 16 
17 18 19 20 
    21 22 23 24 
25 26 27 28 
    29 30 31 32 

あなたは(擬似Javaで)このような再帰的なアプローチを使用することができます

bool place(int i, int start) { 
    if (i == 8) { 
     if (allOccupied()) { 
      print(); 
      return true; 
     } 
    } else { 
     for (int j = start, j < 32; j++) { 
      int row = j/4; 
      int col = 2 * (j % 4) + row % 2; 

      // add bishop at (col, row) 
      // save occupancy matrix 
      // add threat by (col, row) to matrix 

      if (place(i + 1, j + 1)) return true; 

      // revert matrix to saved matrix 
      // remove bishop from (col, row) 
     } 
    } 

    return false; 
} 

をし、それを開始

place(0, 0); 
+0

あなたはそれを非常に技術的に説明することができ、とても感謝しています。私はあなたのアドバイスを使ってコードを書き直しましたが、(i == 8)、すべてのスペースが占有されていない場合の対処方法はまだ分かりません。私はそれが何らかの他の枝であるべきだと思う傾向があります。 – Unknown

+0

付録:私は単純にfalseを返すことができますが、その場合、プログラムは8人のビショップの位置を変更しようとしますが、解決策は決して出ません。その場合、私は一歩以上後退しなければなりません。 – Unknown

+0

あなたが解決策を見つけて、ボードの状態を元に戻す前に呼び出し元の再帰関数に 'true'値を伝播した場合にのみ' true'を返す場合、解答が見つかると、ボードはすべてのビショップを正しく配置する必要があります。 (if(place(i + 1、j + 1))が真を返すif( 'if(place)(place)); –

0

あなたはこのような何か行う必要があります。私たちは場所がpaticular司教のために良いかそうでないかどうかを確認し、それに応じて、我々は解決策があること下がって見つからない場合は、司教のカウントをインクリメントすることができます

public boolean placeBishops (int bishop){ 
    if(bishop == 8){ 
     if(allSpaceOccupied()){ 
      //Print the board here, i.e found the solution 
      //also check the indexing of the bishop, 
      //i have assumed that they start from 0 
      return true; 
     }else{ 
      return false; 
     } 
    } 
    for (int row = 0; row < N; row++) { 
     // check if bishop can be placed 
     if (canPlace(solution, row, bishop)) { 
      // place the bishop 
      solution[row][bishop] = 1; 
      boolean found = placeBishops(bishop+1); 
      if(found == true) return true; 
      solution[row][bishop] = 0; 
     } 
    } 
    return false; 
} 

を現在のビショップインデックスとそのビショップの対応する行についてsolution arrayをリセットして、別の解決策を探すことができます。

+0

これは、canPlaceメソッドがすべての条件(クイーンズ問題のように:行、列、または対角線にクイーンがないかどうかをチェックして配置する)をチェックした場合に問題ありません。ここでcanPlaceメソッドは、ビショップが四角形の対角線にないかどうかをチェックするだけです(そのような場所にビショップを置くことは意味がないためです)。しかし、それはまた、8を置くことができ、すべてのスペースが占有されないことを意味する。だから私は何らかの理由でallSpaceOccupied()メソッドを含める必要があると信じています... – Unknown

+0

関数は何のためにallspaceoccupiedしますか? – uSeemSurprised

+0

すべてのスペースが占有されているかどうかをチェックし、trueまたはfalseを返します。 1 XXXXXXX 1 xxxxxxの0 1 xxxxxは0 0 1 XXXX 0 0 0 1 XXXX 0 0 0 1 xxxxxは0 0 1 xxxxxxの0 1 XXXXXXX :私たちはこのような司教を配置することができcanPlaceを使用して例えば 、 しかし、すべてのスペースが占有されているわけではありませんので、別のソリューションを探す必要があります – Unknown

関連する問題