八皇后位运算解 N-Queen II Leetcode

思路其实还是每使用一位就把横着,和左斜方,右斜方的位站上,但是用位运算就有不一样神韵。

先看代码:

int num;
	int upper;
	public int solve(int n){
		upper=(1<<n)-1;
		dp(0,0,0);
		return num;
	}
	
	public void dp(int row, int ld,int rd){
		System.out.println("dp:  "+Integer.toBinaryString(row)+"\t"+Integer.toBinaryString(ld)+"\t"+Integer.toBinaryString(rd));
		int pos,p;
		if(row!=upper){
			pos=upper&(~(row|ld|rd));
		//	System.out.println("pos= "+Integer.toBinaryString(pos));
			while(pos!=0){
				p=pos&(-pos);
				pos=pos-p;
				dp(row+p,(ld+p)<<1,(rd+p)>>1);
			}
		}else
			num++;
	}

主要精妙在这几个地方:容易看出来这是个dp,思路和普通解基本相同。

精妙1. 用row ld rd表示了横竖斜三个方向上的数据,用1表示占用,0表示可以。


精妙2. 用pos=upper&(~(row|ld|rd))来表示当前可行位置。 这个等会细说。


精妙3. 用p=pos&(-pos)表示第一个非0位。这个涉及到了负数在计算机里的表示。

byte在计算机里是8位,integer是32位,但是Integer.max_value 是(2<<31)-1 为什么?

因为剩下的第32位上是1的数都用来表示负数了,对于任何正整数v,他的负数表示为

~(v-1)

所以6&(-6)=2;

pos里面是用1表示可用,0表示不可用。


精妙4, 就是那个调用dp了,这里连上精妙2一起说一下。

其实我们很容易想到用横竖斜三种方式来表示三个纬度,第四个纬度自动步进1。问题就在于表述形式。在这里row ld rd都是用位来表示,在当前循环中,ld,rd,row都表示该列上被占用的位。 但这是怎么实现的呢?

1. row很容易理解,p为几,第几行就被占了,这没的说。就是ld,rd

2. 注意到列是步进的,也就是说,你在这一列,p占了第3行,下一列,一定被占在第4行上,和在第2行上。到了下下列,一定占在第1行和第5行上。这就是ld,和rd了。

(ld+p)<<1 不就是把所有的位左移1位挡住第4位么?

(rd+p)>>1 挡住了不就是第二位么?

第二次计算完了,到了下下列,再移动,挡住的不就是1行和5行了么?


这就是神

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值