暴力递归-N皇后问题以及优化

在N*N的棋盘上摆N个皇后,要求任意两个皇后不同行,不同列,不在一条斜线上,给定一个整数n,返回n皇后的摆法有多少种。
例如:n=1 返回1
n=2 返回0
n=3 返回0
n=8 返回92

N皇后问题

public class NQueens {
    public static int num1(int n){
        if (n < 1){
            return 0;
        }
        int[] record = new int[n];
        return process1(0, record, n);
    }

    public static int process1(int i, int[] record, int n){
        if (i==n){
            return 1;
        }
        int res = 0;
        for (int j=0; j<n; j++){
            if (isValid(record,i,j)){
                record[i] = j;
                res += process1(i+1, record, n);
            }
        }
        return res;
    }

    public static boolean isValid(int[] record, int i, int j){
		for (int k=0; k<i; k++){
            if (j == record[k] || Math.abs(record[k]-j)==Math.abs(i-k)){
                return false;
            }
        }
		return true;
    }

    public static void main(String[] args) {
//        int res1 = num1(1);
//        int res2 = num1(2);
//        int res3 = num1(3);
//        int res4 = num1(4);
        int res8 = num1(8);
//        System.out.println(res1);
//        System.out.println(res2);
//        System.out.println(res3);
//        System.out.println(res4);
        System.out.println(res8);

//        System.out.println(1<<2);
    }
}

N皇后问题优化

优化的部分是常数比分,对比之前的皇后位置,判断当前有哪些位置可以放置皇后。之前选择数组一个个遍历对比。此处优化借助位运算,32个bit位,当皇后越多时,此方法时间越短

private static int num2(int n){
	//请不要超过32皇后问题,否则请用long等类型
    if (n < 1 || n > 32){
        return 0;
    }
    int upperLimit = n == 32 ? -1 : ((1<<n)-1);
    return process2(upperLimit,0,0,0);
}

//colLim 列的限制,1的位置不能放皇后,0的位置能放皇后
//leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置能放皇后
//rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置能放皇后
private static int process2(int upperLimit, int colLim, int leftDiaLim, int rightDiaLim) {
    if (upperLimit == colLim){
        return 1;
    }

    int mostRightOne = 0;
    //pos 1可以放皇后,0不能,所有候选皇后的位置都在pos上
    int pos = upperLimit & (~(colLim | leftDiaLim | rightDiaLim));
    int res = 0;
    while (pos != 0){
//            mostRightOne = pos & (~(pos-1));
		//最右侧的1提取出来
        mostRightOne = pos & (~pos+1);
        pos = pos - mostRightOne;
        //在最右侧1的位置放皇后,接下来下一行的限制,
		//列限制或上最右侧1的位置,左斜线限制或上最右侧1的位置,再左移一位
		//右斜线限制或上最右侧1的位置,再右移一位
		//>>:带符号右移。正数右移高位补0,负数右移高位补1
		//>>>:无符号右移。无论正数还是负数,高位通通补0
        res += process2(upperLimit, colLim | mostRightOne,
                (leftDiaLim | mostRightOne) << 1,
                (rightDiaLim | mostRightOne) >>> 1);

    }

    return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值