【001】回溯算法(八皇后问题)

序言

经典游戏:八皇后问题

游戏规则:8个皇后在矩阵图里排列,在每个皇后的同一行同一列上,以及同一斜线上不能有其他皇后,否则就会冲突。其示意图如下:

 Java代码实现(带注释)如下:

import java.util.*;

public class n51 {
    // 最外层的list生成
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> solutions = new ArrayList<>();
        int[] queens = new int[n];
        Arrays.fill(queens, -1);
        Set<Integer> columns = new HashSet<>();
        Set<Integer> diagonals1 = new HashSet<>();
        Set<Integer> diagonals2 = new HashSet<>();
        backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
        return solutions;
    }

    // 回溯算法实现 —— 定义方法 backtrack()
    private static void backtrack(List<List<String>> solutions, int[] queens, int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
        // 当行数等于输入个数 n 的时候生成 n皇后矩阵图
        if (row == n) {
            List<String> board = generateBoard(queens, n);
            solutions.add(board);
        } else {
            for (int i = 0; i < n; i++) {
                // 如果列包含 i,则继续返回上面的for循环,否则才进入下一个if判断语句里面
                if (columns.contains(i)) {
                    continue;
                }
                int diagonal1 = row - i;
                if (diagonals1.contains(diagonal1)) {
                    continue;
                }
                int diagonal2 = row + i;
                if (diagonals2.contains(diagonal2)) {
                    continue;
                }
                // 如果都不包含上述元素,并添加这些元素到 queens 数组里面
                queens[row] = i;
                columns.add(i);
                diagonals1.add(diagonal1);
                diagonals2.add(diagonal2);
                // 回溯调用自己 —— 回溯算法的核心思想,和递归一样,回调自己,如果不调用自己,就不叫递归了
                backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2);
                // 当行数 row 等于输入个数 n 的时候生成 n皇后矩阵图后清除上一轮的记录(分别remove掉上一次记录的元素),
                // 并再次进入上面的for循环,开始排列 n皇后
                queens[row] = -1;
                columns.remove(i);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
        }
    }

    /**
     * 打印的效果如下
     * .Q..
     * ...Q
     * Q...
     * ..Q.
     */
    // 生成 n皇后矩阵图
    public static List<String> generateBoard(int[] queens, int n) {
        List<String> board = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[queens[i]] = 'Q';
            board.add(new String(row));
        }
        return board;
    }

//    /**
//     * 打印的效果如下
//     * [., Q, ., .]
//     * [., ., ., Q]
//     * [Q, ., ., .]
//     * [., ., Q, .]
//     * */
//    public static List<String> generateBoard(int[] queens, int n){
//        List<String> board = new ArrayList<>();
//        for (int i = 0; i < n; i++) {
//            String[] row = new String[n];
//            Arrays.fill(row, ".");
//            row[queens[i]] = "Q";
//            board.add(new String(Arrays.toString(row)));
//        }
//        return board;
//    }

    // 测试
    public static void main(String[] args) {
        // 因为是非static方法,所以要先new一个类
        n51 list1 = new n51();
        // 然后通过 变量.方法名 来调用
        int n;
        List<List<String>> list = list1.solveNQueens(n = 5);
//        System.out.println("一行内打印全部" + list);
        int i;  // 在for外面定义变量,为了在最后打印总的结果
        System.out.println("=======换行打印内部的每一个list=======");
        // 先循环外面一层的list
        for (i = 0; i < list.size(); i++) {
            // list.get(i)为里面一层的list,
            List<String> item = list.get(i);
//            System.out.println("=======换行打印内部的每一个list的每一个元素,形成矩阵图=======");
//            // 拿到里面的list之后,给它赋值一个变量,名为item,并再次对这个list进行循环
            // 增强for循环写法
//            for (String str : item) {
//                System.out.println(str);
//            }

            // 普通for循环写法如下
//            for (int j = 0; j < item.size(); j++) {
//                String str = item.get(j);
//                System.out.println(str);
//            }

            System.out.println("内部的第" + i + "个list:" + item);
        }
        System.out.println("\n" + n + "个皇后," + "共" + i + "种排列方法");
    }
}

无注释完整版如下:

import java.util.*;

public class n51 {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> solutions = new ArrayList<>();
        int[] queens = new int[n];
        Arrays.fill(queens, -1);
        Set<Integer> columns = new HashSet<>();
        Set<Integer> diagonals1 = new HashSet<>();
        Set<Integer> diagonals2 = new HashSet<>();
        backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
        return solutions;
    }

    private static void backtrack(List<List<String>> solutions, int[] queens, int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
        if (row == n) {
            List<String> board = generateBoard(queens, n);
            solutions.add(board);
        } else {
            for (int i = 0; i < n; i++) {
                if (columns.contains(i)) {
                    continue;
                }
                int diagonal1 = row - i;
                if (diagonals1.contains(diagonal1)) {
                    continue;
                }
                int diagonal2 = row + i;
                if (diagonals2.contains(diagonal2)) {
                    continue;
                }
                queens[row] = i;
                columns.add(i);
                diagonals1.add(diagonal1);
                diagonals2.add(diagonal2);
                backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2);
                queens[row] = -1;
                columns.remove(i);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
        }
    }

    public static List<String> generateBoard(int[] queens, int n) {
        List<String> board = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[queens[i]] = 'Q';
            board.add(new String(row));
        }
        return board;
    }

    public static void main(String[] args) {
        n51 list1 = new n51();
        int n;
        List<List<String>> list = list1.solveNQueens(n = 5);
        int i;
        System.out.println("=======换行打印内部的每一个list=======");
        for (i = 0; i < list.size(); i++) {
            List<String> item = list.get(i);
            for (String str : item) {
                System.out.println(str);
            }
            System.out.println("内部的第" + i + "个list:" + item);
        }
        System.out.println("\n" + n + "个皇后," + "共" + i + "种排列方法");
    }
}

运行结果如下: 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值