1. 程式人生 > >八皇后位運算解 N-Queen II Leetcode

八皇后位運算解 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行了麼?

這就是神