采用位运算方法:
row表示当前行列禁位,ld表示当前行左斜线禁位,rd表示当前行右斜线禁位。
row|ld|rd表示当前行所有禁位。其反与upperlim交限制位数。所以当前行所有可用位置表示为:
pos = upperlim & (~(row | ld | rd ));
从右往左进行方案的选择
p表示最右边的可用位置
p = pos & (~pos + 1);
占用该位置后pos=pos-p
,进行下一行。此时row = row | p
,ld = (ld | p) << 1
,rd = (rd | p) >> 1
,进入下一行递归。
DFS(row|p,(ld|p)<<1,(rd|p)>>1,n,upperlim);
直到某一行没有可用位置,结束,sum+1。递归返回后,检查pos还有没有其他可行方案,这即是使用while(pos)
的原因。
完整代码:
class Solution {
public:
int totalNQueens(int n) {
int upperlim=(1<<n)-1;
int sum=0;
DFS(0,0,0,sum,upperlim);
return sum;
}
void DFS(int row,int ld,int rd,int &n,const int upperlim){
int pos,p;
if(row==upperlim) n++;
else{
pos=upperlim & (~(row | ld | rd));//找到所有可行位置,为0则已不存在可行位置,和upperlim交防止位数变化
while(pos){
p=pos &(~pos+1);//最右边的可行位置
pos=pos-p;
DFS(row|p,(ld|p)<<1,(rd|p)>>1,n,upperlim);
}
}
}
};