(三)回溯算法

一、基本概念

   回溯算法实际上是一个枚举的搜索尝试过程,主要在搜索尝试过程中寻求问题的解,当发现满足求解条件时,则将路径存储,否则不做任何处理。

二、设计思想

   回溯思想:穷举搜索

   回溯设计:(1)域:设置一个数组arr用于存放可达路径,设置一个数组List<arr>用于存放所有可达路径

                  (2)问题转化:问题转化为求解可达路径下一步如何走的问题

                  (3)方法逻辑:给出可达路径的终止条件,满足条件时存储路径,否则将大问题分割成多个规模较小的相同问题,递归求解。

、问题分析

    下面以八皇后问题进行说明,原题表述如下:

    在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

    算法选型:

    八皇后问题实质是对可达路径的穷举求解,因而应该选用回溯算法    

    题目分析:

    由于皇后不能处于同一行,因此按行来规定皇后,第一行放第一个皇后,第二行放第二行皇后,直到所有行放完;在上述过程中涉及到两点,首先每行的一个皇后放置在什么位置,这是不确定的需要穷举,但必须满足与前面皇后不能同一列,也不能同一对角线

    算法逻辑:

    (1)域:array用于存放八皇后的正确摆放方式,storage用于存储所有的摆放方式

    (2)问题转化:问题转化为求解第n个皇后放置在什么位置的问题,即:void placeQueue(int n);

    (3)终止条件:当摆放第8个皇后时即为终止信号,说明当前路径符合要求即为存储

    (4)子问题递归:第n个皇后有多种方法可以放在任意位置,因为需要for穷举,当第n个皇后放置后如果与前面放置的n-1个皇后满足上述限制条件,则继续放置n-1个皇后,与前述完全一致,递归即可

    代码示意如下所示:

public class Example {

    private static ArrayList<ArrayList<Integer>> storage = Lists.newArrayList();

    /**
     * 总皇后数,此时设置为8皇后在8X8棋盘的摆放
     **/
    private static int max = 8;

    /**
     * 存放八皇后的摆放方式,第一个皇后摆在array[0]列,第二个摆在array[1]列,.....
     **/
    private static int[] array = new int[max];

    /**
     * @param n 当前是第几个皇后(从0开始计算)
     **/
    private static void placeQueue(int n) {
        // 一行摆放完毕
        if (n == max) {
            ArrayList<Integer> arrayList = Lists.newArrayList();
            for (int i = 0; i < max; i++) {
                arrayList.add(array[i]);
            }
            storage.add(arrayList);
            return;
        }
        //从第一列开始放值,然后判断是否和本行本列本斜线有冲突,如果OK,就进入下一行的逻辑
        for (int i = 0; i < max; i++) {
            array[n] = i;
            // 判断是否符合八皇后条件,符合则摆放下一个皇后,否则回退继续尝试摆放
            if (judgeLegal(n)) {
                placeQueue(n + 1);
            }
        }
    }

    /**
     * @param n 摆放的当前皇后的编号, array[n]为要当前摆放的皇后的位置,array[0~n-1]为前n-1已经摆放的皇后位置
     * @func 判断是否符合八皇后条件
     * 分析: 假设一个皇后所在位置为n列,位置为arr[n],坐标为(n, arr[n]), 另一个皇后的坐标为(i, arr[i]),
     * 如果两个皇后在一条对角线上, 画图根据数学分析可知,则必有Math.abs(n-i) == Math.abs(arr[n], arr[i]);
     * 如果两个皇后在不同行的同一位置则必有arr[n] == arr[i]
     **/
    private static boolean judgeLegal(int n) {
        for (int i = 0; i < n; i++) {
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        placeQueue(0);
        for (int i = 0; i < storage.size(); i++) {
            System.out.println(storage.get(i));
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/huaiheng/p/12906288.html