经典N皇后问题

本文介绍了N皇后问题的解决方案,包括暴力递归法和位运算优化法。这两种方法分别通过递归和位运算技巧在n×n的棋盘上放置n个皇后,确保它们互不攻击。代码实现详细展示了两种算法,并给出了不同n值下的解法数量。
摘要由CSDN通过智能技术生成

N皇后问题

n 皇后问题:
如何将 n 个皇后放置在 n×n 的棋盘上,
并且使皇后彼此之间不能相互攻击(不在同一行,同一列,同一对角线上)。
给定一个整数 n ,返回有多少种摆放方法。

两种解法

/**
 * @author IT00ZYQ
 * @Date 2021/4/8 21:50
 **/
public class N皇后 {

    /**
     * 暴力递归法
     * @param n
     * @return
     */
    public static int way1(int n) {
        if (n < 0) {
            return -1;
        }
        int[] record = new int[n];
        return wayFun1(0, n, record);
    }

    /**
     * @param cur 当前需要的摆放的是第cur个皇后
     * @param n 总共有n-1个皇后需要摆放
     * @param record 前cur-1个皇后摆放的列
     * @return
     */
    private static int wayFun1(int cur, int n, int[] record) {
        if (cur == n) {
            return 1;
        }
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (isValid(record, cur, i)) {
                record[cur] = i;
                res += wayFun1(cur + 1, n, record);
                // 由于每次进行操作都会修改record[cur]的值,此处不需要还原现场
            }
        }
        return res;
    }

    private static boolean isValid(int[] record, int i, int j) {
        for (int k = 0; k < i; k++) {
            // 用于判断(k, record[k]) 与 (i, j)是否在同一列或者同一对角线上
            if (record[k] == j || Math.abs(i - k) == Math.abs(j - record[k])) {
                return false;
            }
        }
        return true;
    }


    /**
     * 通过位运算加快常数级运算
     * @param n n皇后问题
     * @return 摆放方案
     */
    public static int way2(int n) {
        // 位运算方法最高只支持32皇后问题
        if (n < 0 || n > 32) {
            return -1;
        }
        // (1<<n)-1 -> 如果n是8皇后,则其二进制表示为00...00 1111 1111
        // 即最后8位为1,其他位都为0
        int limit = n == 32 ? -1 : (1 << n) - 1;
        return wayFun2(limit, 0, 0, 0);
    }


    public static int wayFun2(int limit, int colLimit, int leftLimit, int rightLimit) {
        // 当列限制已满,说明已摆放了n皇后,返回1
        if (colLimit == limit) {
            return 1;
        }

        int res = 0;
        // t表示在colLimit、leftLimit、rightLimit限制下,还有多少种可尝试的方案
        // 可尝试的位置为1,被限制的位置为0
        int t = limit & ~(colLimit | leftLimit | rightLimit);
        while (t != 0) {
            // 获取t中最右边的1
            int p = t & (~t + 1);
            res += wayFun2(limit,
                    colLimit | p,
                    (leftLimit | p) << 1,
                    (rightLimit | p) >>> 1);
            t -= p;
        }
        return res;
    }

    public static void main(String[] args) {
       for (int i = 0; i <= 12; i++) {
            System.out.printf("当前为%d皇后问题,暴力递归法答案:%d,位运算改进法答案:%d\n", i, way1(i), way2(i));
        }
    }
}

问题答案

当前为0皇后问题,暴力递归法答案:1,位运算改进法答案:1
当前为1皇后问题,暴力递归法答案:1,位运算改进法答案:1
当前为2皇后问题,暴力递归法答案:0,位运算改进法答案:0
当前为3皇后问题,暴力递归法答案:0,位运算改进法答案:0
当前为4皇后问题,暴力递归法答案:2,位运算改进法答案:2
当前为5皇后问题,暴力递归法答案:10,位运算改进法答案:10
当前为6皇后问题,暴力递归法答案:4,位运算改进法答案:4
当前为7皇后问题,暴力递归法答案:40,位运算改进法答案:40
当前为8皇后问题,暴力递归法答案:92,位运算改进法答案:92
当前为9皇后问题,暴力递归法答案:352,位运算改进法答案:352
当前为10皇后问题,暴力递归法答案:724,位运算改进法答案:724
当前为11皇后问题,暴力递归法答案:2680,位运算改进法答案:2680
当前为12皇后问题,暴力递归法答案:14200,位运算改进法答案:14200
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

it00zyq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值