再帰的アルゴリズムのアプリケーション例-8つのクイーンアルゴリズム

エイトクイーンの問題

バックトラッキングアルゴリズムの古典的なケース

バックトラッキングアルゴリズムの典型的なケース。この問題は、1848年にチェスプレーヤーのMax Bethelによって提起されました。8つのクイーンを8X8のチェス盤に配置して、お互いに攻撃できないようにします。つまり、2つのクイーンが同じ行の外に出ることはできません。同じ列または同じ対角線で、いくつの方法があるか尋ねます。

思考分析

  1. 最初の女王は最初の行と最初の列に配置されます
  2. 2番目のクイーンを2番目の行の最初の列に配置し、0Kかどうかを判断します。問題がある場合は、引き続き2番目と3番目の列に配置し、すべての列を順番に並べて、適切なものを見つけます。
  3. 3番目の女王に進み、1列目と2列目を失神させます... 8番目の女王が競合しない位置に配置できるようになるまで、正しい解決策が見つかったと見なされます。
  4. 正しい解が得られたとき、スタックが前のスタックにロールバックすると、それはバックトラックを開始します。つまり、最初の女王は、すべての正しい解を最初の列に入れ、すべてを取得します。
  5. 次に、戻って最初の列に進みます。2番目のクイーンを2番目の列に配置してから、手順1、2、および3を繰り返します。

**説明:**理論的には、チェス盤を表すために2次元配列を作成する必要がありますが、実際には、1次元配列を使用してアルゴリズムを通じて問題を解決できます。arr[8] = {0,4 、7、5、2、6、1、3)は正の解を表します

対応するarr添え字は行数、つまりクイーンの数を示します。arr[i] = val、valはi +1番目の行のval + 1番目の列に配置されたi + 1番目のクイーンを示します。

効率は比較的低い可能性があり、欲張りアルゴリズムなど、後で最適化するアルゴリズムもあります。これについては、次の注記で説明します。

コード

package com.wang.Recursion;
/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 19:45
 * @Description TODO
 * @pojectname 八皇后问题
 */
public class Queue8 {
    
    
    //定义一个max表示共有多少个皇后
    int max = 8;
    //定义数组array,保存皇后放置的位置,比如arr[8]={0,4,7,5,2,6, 1,3}
    int[] array = new int[max];
    static int count = 0;
    public static void main(String[] args) {
    
    
        //测试
        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.println("一共有"+count+"次解法");
    }
    //编写一个方法,放置第n个皇后
    //特别注意:check是每一层递归时,进入到check都有for循环,因此会有回溯
    private void check(int n){
    
    
        //如果n = max,皇后放完了,
        if (n == max){
    
    
            print();
            return;
        }
        //没有放完的话,依次放入皇后,判断是否冲突
        for (int i = 0; i < max ; i++) {
    
    
            //先把当前的皇后n,放到改行的第一列
            array[n] = i;
            //判断当放置了第n个皇后到i列时,是否冲突
            if (judge(n)) {
    
    
                //不冲突,接着放n+1个皇后,即开始递归
                check(n+1);
            }
            //如果冲突,就继续执行array[n] = i;这个时候i已经++了,就是放到了下一列
        }
    }

    /**
     //查看当我们放置第n个皇后时,就去检测该皇后是否和前面已经摆好的皇后冲突
     * @param n 表示第n个皇后
     * @return
     */
    private boolean judge(int n){
    
    
        for (int i = 0; i <n ; i++) {
    
    
            //array[i] == array[n]表示第n个皇后是否和前面i个皇后是否在同一列
            //Math.abs(n-i) == Math.abs(array[n] - array[i]表示第n个皇后是否和第i个皇后在同一斜线
            if (array[i] == array[n] ||Math.abs(n-i) == Math.abs(array[n] - array[i] )){
    
    
                return false;
            }
        }
        return true;
    }

    //将皇后拜访的位置打印出来
    private void print(){
    
    
        count++;
        for (int i = 0; i <array.length ; i++) {
    
    
            System.out.print(array[i]+"");
        }
        System.out.println();
    }
}

おすすめ

転載: blog.csdn.net/qq_22155255/article/details/111462168