回溯算法-八皇后

回溯算法-八皇后

今天学习了下回溯算法,顺便看了下经典案例:八皇后问题。

该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

回溯算法的搜索逻辑是深度优先,即,从一条路往前走,能进则进,不能进则退回来,换一条路再试。
先直接晒代码:

/**
 * Created by cxx on 2017/6/20.
 */
public class MyQueen {
    //搜索过程中动态产生
    //解空间最小单元
    private int[] result;

    private int num = 1;

    //定义皇后个数(可以是9皇后,10皇后。。。)
    private int queens;

    public MyQueen(int queens){
        this.queens = queens;
        result = new int[this.queens];
    }
    //遍历-深度优先
    public void backTrack(int i){
        if (i < this.queens){
                for (int j = 0 ; j < this.queens; j++){
                    if (i==0 || isKilled(i,j)){
                        result[i] = j;
                        backTrack(i+1);
                    }
                }
        }else{
            showResult();
        }
    }
    //游戏规则->转成数学问题->程序
    public boolean isKilled(int i , int j){
        for (int k=i-1; k >=0 ; k --){
            if (result[k] == (k+(j-i)) || result[k] == ((j+i)-k) || j == result[k]) {
                return false;
            }
        }
        return true;
    }
    //输出解空间
    public void showResult(){
        System.out.println("\n 解:"+num);
        for (int i = 0 ; i < this.queens ; i++){
            for (int j = 0 ; j < this.queens ; j++){
                if (result[i]  == j ){
                    System.out.print("*");
                }else {
                    System.out.print(".");
                }
            }
            System.out.println();
        }
        num++;
    }

    public static void main(String[] args) {

        MyQueen myQueen = new MyQueen(8);
        long c = System.nanoTime();
        myQueen.backTrack(0);
        System.out.println("end:"+(System.nanoTime()-c)/1000);

    }
}

首先定义解空间:int[] result。

使用int[]简化输出结果集,存储着每行皇后所处位置的下标。result[0] = 5 表示第一行皇后位于索引下表为5的位置(.....*..);

然后开始遍历,目的是组织解空间,即,给result赋值。

逐行遍历,找到该行的皇后后,立即动身寻找下一行的皇后,以先找出一个完整的result为优先(深度优先)。凑不出一个result就舍弃(每个result的i必须凑到8,不足的则舍弃)。找到后回来继续遍历。

遍历的筛选条件从题目中来,转化成数学模型即三个简单的函数:

y=x+k(正斜线)
y=-x+k(反斜线)
y=k(竖线)

由于横向遍历,所以无需考虑会在同一条横线上的情况。满足三个函数任意,即皇后可互相攻击,就舍弃。
运行结果:

 解:1
*.......
....*...
.......*
.....*..
..*.....
......*.
.*......
...*....

 解:2
*.......
.....*..
.......*
..*.....
......*.
...*....
.*......
....*...

 解:3
*.......
......*.
...*....
.....*..
.......*
.*......
....*...
..*.....

这里没有贴出所以的输出,一共是92个。感兴趣的可以自己运行一下试试。该文章是学习笔记,有问题的话欢迎指出。

猜你喜欢

转载自blog.csdn.net/qq250782929/article/details/73520181