回溯算法-N皇后问题

189 阅读2分钟

问题

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

代码

    public static List<String[][]> solves = new LinkedList<>();
 
    public static void main(String[] args) {
        solveNQueens(8);
        print();
    }
    
    /**
     * N皇后问题
     * 输入棋盘边长 n,返回所有合法的放置
     *
     * @param n
     * @return
     */
    public static List<String[][]> solveNQueens(int n) {
        //初始化8*8的棋盘
        String[][] board = initBoard(8);

        pushQueens(board, 0);

        return solves;

    }
    
    /**
     * 初始化N*N的棋盘
     *
     * @param n
     * @return
     */
    public static String[][] initBoard(int n) {
        String[][] board = new String[n][n];
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                board[i][j] = ".";
            }
        }
        return board;
    }
    
     /**
     * 保存棋盘副本
     * @param board
     * @return
     */
    public static String[][] copy(String[][] board) {
        String[][] copy = new String[board.length][board[1].length];
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                copy[i][j] = board[i][j];
            }
        }
        return copy;
    }
    
    /**
     * 回溯算法放置皇后在board[row][col]
     * @param board
     * @param row
     * @return
     */
    public static void pushQueens(String[][] board, int row) {
        if (row == board.length) {
            solves.add(copy(board));
            return;
        }
        int n = board[row].length;
        for (int col = 0; col < n; col++) {
            if (!isValid(board, row, col)) {
                continue;
            }
            board[row][col] = "Q";
            pushQueens(board, row + 1);
            board[row][col] = ".";
        }

    }
    
     /**
     * 判断是否可以将皇后放置在board[row][col]
     * @param board
     * @param row
     * @param col
     * @return
     */
    public static boolean isValid(String[][] board, int row, int col) {
        int n = board.length;

        // 检查列是否有皇后互相冲突
        for (int i = 0; i < row; i++) {
            if (board[i][col] == "Q") {
                return false;
            }
        }

        //检查右上方
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (board[i][j] == "Q")
                return false;
        }

        //检查左上方
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == "Q")
                return false;
        }

        return true;
    }
    
    /**
     * 打印结果
     */
    public static void print(){
        for (int k = 0; k < solves.size(); k++) {
            System.out.println("---第" + (k + 1) + "种放置方法如下---");

            String[][] boards = solves.get(k);

            for (int i = 0; i < boards.length; i++) {
                for (int j = 0; j < boards[i].length; j++) {
                    if (j == boards[i].length - 1) {
                        System.out.println(boards[i][j] + "  ");
                    } else {
                        System.out.print(boards[i][j] + "  ");
                    }
                }
                if (i == boards.length - 1) {
                    System.out.println("      ");
                }
            }
        }
    }

运行结果