专题二 · 1009

代码及解释

#include <stdio.h>
#include <stdint.h>

// 经典的 N皇后问题,以前讲剪枝的时候就刷过
//
// 人畜无害的数据范围,普通搜索也不会出问题
// 但是第一次做竟然 TLE 了……
// 然后改成位运算优化的,又 TLE了……
// 然后改成 C 语言,AC了  ?!奇葩的评测机


// l mid r三个变量分别是标记一个棋子对左下 正下和右下的影响
int search(int n, uint16_t l, uint16_t mid, uint16_t r, int depth) {
    if (depth == n) {
		return 1;
    } else {
        
        // 当前能不能放棋子
		uint16_t p = l | mid | r;
        
        // 逻辑非蕴含 !(p -> p + 1) <=> ((~p)&(p+!))
        // 得到右边的第一个 0 位
		uint16_t pos = (~p) & (p + 1);
        
        
        // 当前层的可行数
		int ans = 0;

        // 边界是 p == 1 << n
		while (pos < 1 << n) {
            // 在第一个能下子的地方下子
            // 向左下的斜线
			uint16_t tl = (l | pos) << 1;
            // 正下方的斜线
			uint16_t tmid = mid | pos;
            // 向右下的斜线
			uint16_t tr = (r | pos) >> 1;
            
            // dfs 下一层
			ans += search(n, tl, tmid, tr, depth + 1);
            
            // 把已经遍历过的地方标记为不可下
			p = p | pos;
            //继续再求第一个可下子的位置
			pos = (~p) & (p + 1);
		}
		return ans;
	}
}

int main() {

	int n;
	scanf("%d", &n);
	while (n) {
		int ans = search(n, 0, 0, 0, 0);
		printf("%d\n", ans);
		scanf("%d", &n);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值