回溯法:N皇后问题(Java)

题目描述:

思路:首先要创建一个二维数组初始化棋盘,根据题意,可以先在第一行第一列放一个皇后,由于皇后会攻击处在同一行、同一列或同一斜线上的棋子,就需要再定义一维数组来分别判断它的列冲突、左斜线上的冲突和右斜线上的冲突,因为已经找到第一行的位置了,显然该行其它列已经放不了皇后,就递归调用下一行,然后通过循环列进行第二行的列处理,以此往复。

上面用递归的原因是:在第一行第一列放皇后不一定是最后能放下最多皇后的方法,因此就采用递归-回溯的办法,如果发现这个放法行不通(某一次递归调用的次数没有n次,说明有行放不了皇后,不是最优的放法)就回溯到最开始的状态,再在第一行的第二列放皇后。能完整放满所有行的放法就是最优的,将其打印,当处理完第一行所有列的皇后放法后,就相当于找完了所有的放法。

完整代码:

public class NQueen {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入边长n:");
        int n = scanner.nextInt();
        boolean[] y = new boolean[n];   // 记录列冲突
        //根据规律发现在 n*n 的棋盘上一共有 2 * n - 1 左/右斜线
        boolean[] left = new boolean[2 * n - 1];  // 左斜线上冲突
        boolean[] right = new boolean[2 * n - 1];  // 右斜线冲突
        char[][] table = new char[n][n];  //二维数组表示棋盘
        init(table);  //初始化
        dfs(0, n, table, y, left, right);  //初始递归调用
    }

    static void init(char[][] table){
        for (char[] t : table) {
            Arrays.fill(t, '.');  //将棋盘初始化成"."
        }
    }

    static void dfs(int i, int n, char[][] table, boolean[] y, boolean[] left, boolean[] right) {  //递归方法,用来处理每一行皇后的放置
        if (i == n) {   // 处理完所有行,找到一个解了,可以结束递归
            System.out.println("-------------------");
            for (char[] t : table) {  //重新遍历棋盘,打印皇后的位置
                System.out.println(new String(t));
            }
            return;
        }
        for (int j = 0; j < n; j++) {  //列的循环
            if (y[j] || left[i + j] || right[n - 1 - (i - j)]) {  //如果列,左斜线,右斜线上有冲突应该跳过这次递归进入下次循环
                continue;
            }
            table[i][j] = 'Q';  //在当前行的当前列放入皇后
            y[j] = left[i + j] = right[n - 1 - (i - j)] = true;  //更新,ca[j]:此列  cb[i + j]:左斜线  cc[n - 1 - (i - j)]:右斜线 均有冲突(true)
            dfs(i + 1, n, table, y, left, right);  //继续递归,开始在第 i+1 行(下一行)放入元素
            //回溯,若递归没有成功,能恢复到递归前的状态
            table[i][j] = '.';
            y[j] = left[i + j] = right[n - 1 - (i - j)] = false;
        }
    }
}
下面是一个基于回溯法Java 代码实现,用于解决 n 皇后问题: ```java public class NQueens { private int[] queens; // 存放皇后所在列的位置 private int n; // 皇后个数 private int count; // 解法数 public int solveNQueens(int n) { this.n = n; queens = new int[n]; count = 0; backtrack(0); return count; } private void backtrack(int row) { if (row == n) { // 找到一组解 count++; return; } for (int col = 0; col < n; col++) { if (isValid(row, col)) { // 判断该位置是否可以放置皇后 queens[row] = col; backtrack(row + 1); } } } private boolean isValid(int row, int col) { for (int i = 0; i < row; i++) { if (queens[i] == col || Math.abs(row - i) == Math.abs(col - queens[i])) { return false; // 同一列或同一对角线已有皇后 } } return true; } } ``` 在这个实现中,`queens` 数组存放每行皇后所在的列位置,`n` 表示皇后个数,`count` 初始为 0,用于统计解法数。`solveNQueens` 方法返回解法数,内部调用 `backtrack` 方法进行回溯搜索。`isValid` 方法用于判断该位置是否可以放置皇后,即该位置所在列、左上对角线、右上对角线是否已经有皇后。 回溯法是一种常用的解决搜索问题的算法,其思路是通过枚举所有可能的解,找到符合条件的解。在 n 皇后问题中,我们从第一行开始,枚举该行的所有位置,判断该位置是否可行,如果可行则继续递归搜索下一行,如果不可行则回溯到上一行。这样,当找到一组解时,我们就可以记录下来并开始寻找下一组解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值