エイトクイーン問題 - 古典後戻り

エイトクイーン問題

エイトクイーン問題は、古い、よく知られた問題であるアルゴリズムをバックトラックの典型的なケースです。問題は、マックス・ベテルが1848年に提示した国際チェスプレーヤーです:8つのクイーンズの国際チェス8×8のグリッド上に置かれ、それがお互いを攻撃することはできません、任意の二つの王妃が同じ行にすることはできません、です、同じ行または同じスラッシュと尋ねたどのように多くの振り子方式に。ガウスは、プログラムの76種類があると思います。1854年にはベルリンで異なるチェス雑誌に異なるソリューションの40種類を発表し、その後、誰かがグラフ理論を使用した結果の92種類を解きます。

バックトラックの思考

アルゴリズムをバックトラックの基本的な考え方は次のとおりです。もう一度、道路のため、入力しないに戻った後、そこに入ること、前方に一つの方法を出て行きます。典型的な問題のアルゴリズムをバックトラック八女王は女王を置くための最初のステップである、そして要件に沿って、第二のステップは、要件を満たすために何の位置が存在しない場合、我々は最初の女王、最初の再リリースの位置を変更する必要があり、最初のクイーンを置きます位置あなたがそれに修飾位置を見つけるまで2女王。迷路に検索バックを使用して次の道に進み、前の交差点に戻り、その後、どこにもその道路のリードで、非常に一般的です。それは徹底的な方法を意味バックトラック。しかし、機能をプルーニングアルゴリズムの使用をバックトラック、いくつかのノードが最終状態(すなわち、状態への答え)、それにより、還元生成状態空間ツリーノードに到達することができない切断。バックトラックはしてとのジャンプで両方の体系的な検索アルゴリズムです。これは、ルートから検索ソリューションスペースツリーを開始し、問題のすべてのソリューションを含む溶液スペースツリー、深さ優先の戦略です。このアルゴリズムは、解空間ツリーいずれかのノードを検索するときに解決策は確かにある場合、ノードは常に判決前に問題を含んでいません。、その後、システムはノードをルートとするサブツリーを検索するためにスキップし、その祖先ノードに層バックによって層を肯定的が含まれていません。それ以外の場合は、サブツリーを入力し、検索は深さ優先の戦略を継続します。ルートに戻って、に使用問題に、すべてのソリューションでバックトラック、およびすべてのサブ樹木の根は、検索の終了前にオーバーしています。そして、検索が終了する可能性がある場合、問題の解決策を問題への解決策を求めているすべてのバックトラックのため。深さ優先探索アルゴリズムにおけるシステムの問題に対するこの解決策は、問題の組み合わせの多数の一部に適した溶液、バックトラックと呼ばれています。

八のクイーンズ達成

これは私がブログ記事溶液中で読んだ、私は8つのクイーン問題の本質を理解するために初めて、彼は個人的に非常に友好的と信じて始めた人のために、オリジナルのアドレスは次のとおりです。https://cloud.tencent.com/developer/article/1470987 。コードのコメントは、これは、特定の実装の文字通りの解釈ではない、非常にはっきりしている、次のとおりです。

書式#include <iostreamの>

INT queenCell [ 8 ] [ 8 ] = { 0 }。
INT queenPlace [ 8 ] = { 0 }。
int型のカウント= 0 ;

ボイド printQueen(){   // 二次元アレイ印刷
  のためにINT I = 0 ; I < 8 ; ++ I){
     ためINT J = 0 ; J < 8。 ; ++ J){
       IF(queenPlace [I] == J){
        printf(" Q " );
      } {
        printf(" * " );
      }
    }
    printf(" \ n個" );
  }
  printf(" ----数:%D ----- \ N "、++ のカウント)。
}

ボイド eightQueen(int型の列){
   ためのint型 COL = 0、COL < 8。 ; COL ++){   // 列がクイーンに配置することができれば反復列見出し、この層の役割は、最初の行、最初の列を問い合わせるためのループラインである
    場合(queenCell [行] [COL] == 0){   // 最初の行線と、第二の女王は、COL列を配置することができる
      ためINT NextRow =ロウ+ 。1 ; NextRow < 8。、NextRow ++){   // この層をforループ役割は、斜め下方であり、それは0ではないの下 
        queenCell [NextRow] [COL] ++;   // ゼロでないとしてマークされ、同一列(直下)の異なる行は、女王が列に配置されていないことを示し
        IF( COL - NextRow行+> = 0){   //層行ROWを循環する、最初の列に正の対角位置がCOLゼロ、標識されている 
            [行+ COL-NextRow] ++ queenCell [NextRowを];   //は女王がこれらの場所に配置することができない表す
        }
         IF(COL + NextRow -行< 。8){    // 最初の行の行の層を介して位置ループ、COLカラムは抗対角の非ゼロ標識 
            ++ queenCell [NextRow] [COL + NextRow-行] 
        }
      }
      queenPlace [行] = COL;   // レコードディレクトリ列に配置され、行ROW列クイーン
      IF(==行7){   // 女王は女王が充填されている場合を言うする各行を、配置されている場合、印刷レイアウトクイーン
        printQueen();
      }  {   // 再帰的には次の行に配置されたクイーン継続 
        (行+ eightQueenを1。 )。  
      }

      以下のためにINT NextRow =ロウ+ 。1 ; NextRow < 8。、NextRow ++){   // バック、女王の最初の行の最初の行にCOL列に、それがその列に配置されないように? 
                                                             // 答えは、この行の他の列にクイーンのために最も外側のループを使用して、アルゴリズムの最も外側のループを介して行われる
         // 最初の行の行、列列が最初の場所クイーン、及びだけ下回っていない復元する必要はないのでマーク、同じ列の非ゼロ行の顕著な減少は、直ちにマーカー以下、すなわち、回収位置、異なる                                                             
        queenCell [NextRow] [COL] - ;
         IF(COL - NextRow行+> = 0){   // 還元標識された陽光柱列の対角線上の行の位置の行 
            queenCell [NextRow] [行+ COL-NextRow] - 
        }
        IF(COL + NextRow -行< 。8){   // 逆の対角位置マーク列欄に、最初の行線を復元 
            queenCell [NextRow] [COL-行NextRow +] - 
        }
      }
    }
  }
}

INT メイン(){
    eightQueen(0 )。
    リターン 0 ;
}

八のクイーンズ2を達成します

次の実装は、実際には、より賢い、思考は以下のように、コードが実装されていますが、8人の女王の問題の本質を理解している場合、この方法をお勧めします、非常に明確である、省スペースの2次元配列のソリューションに比べオタク時間ソリューションの議論の余地のない王、次のとおりです。

書式#include <iostreamの>

INT queenPlaceは、[ 8は ] = { 8は };   // グローバル変数、添字は行を示し、その列に格納された値は、クイーン示す
int型 COUNT = 0 ;   // カウンタを

ボイド printQueen(){   // 二次元アレイ印刷
  のためにINT I = 0 ; I < 8 ; ++ I){
     ためINT J = 0 ; J < 8。 ; ++ J){
       IF(queenPlace [I] == J){
        printf(" Q " );
      } {
        printf(" * " );
      }
    }
    printf(" \ n個" );
  }
  printf(" ----数:%D ----- \ N "、++ のカウント)。
}

BOOL ISOK(int型の列、int型 COL){   //は、行ラインCOLカラム適切な場所かどうかを決定する
  intを leftup COL = - 1 ;   //は、上側対角線左
  INT rightUp + = COL 1。 ; // 右上対角線
  のためのint型 Iを行= - 1。 ; I> = 0 ; - I){ 
     IF(queenPlace [I] == COL)リターン falseに ;   // クイーンとグリッド上の同じ列
    IF(leftup> = 0 ){
       IF(queenPlace [I] leftup ==)のリターン はfalse ;   // 左上対角線クイーン
    }
     IF(rightUp < 8。){
       IF(queenPlace [I] == rightUp)リターン falseに ;   // 右上対角線女王
    }
     --leftUp; ++ rightUp。
  }
  返す ;
}

ボイド eightQueen(INTの行){
   IF(行== 8){   // 8つのクイーンはよく配置され、印刷ではなく、再帰リターン。
    printQueen();
     戻り
  }
  int型 COL = 0、COL < 8。 ; COL ++){   // 各列は8つのメソッドを有する
    IF(ISOK(行、COL)){     // ミート 
      queenPlace [行] = COL; // 最初の行をCOL列のクイーン行 
      eightQueen(行+ 1);      // 次の行を調べます
    }
  }
}


INT メイン(){
    eightQueen(0 )。リターン 0 ;
}

 

おすすめ

転載: www.cnblogs.com/evenleee/p/11946724.html