Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
我们继续用N-Queens的方法,Time Limit Exceeded,Last executed input:11
int result;
void permutationHelper(int* &nums, int index, int n)
{
if(index == n)
{
bool flag = true;
for(int i = 0; i<n && flag; i++)
for(int j=i+1; j<n; j++)
if((j-i) == abs(nums[j]-nums[i]))
{
flag = false;
break;
}
if(flag)
result++;
}
for(int i = index; i < n; i++)
{
swap(nums[index], nums[i]);
permutationHelper(nums, index+1, n);
swap(nums[index], nums[i]);
}
}
void permutation(int n)
{
int* nums = new int[n];
for(int i = 0; i < n; i++)
nums[i] = i;
permutationHelper(nums,0,n);
}
int totalNQueens(int n) {
// Note: The Solution object is instantiated only once.
result = 0;
permutation(n);
return result;
}
第二种方法:位运算Accepted
long long upperlim;
int totalnum;
void test(long long row, long long ld, long long rd)
{
long long pos;
long long p;
if( row == upperlim)
totalnum++;
else
{
pos = upperlim & ~(row | ld | rd);
while(pos)
{
p = pos & (~pos + 1);
pos = pos - p;
test(row+p, (ld+p)<<1, (rd+p)>>1);
}
}
}
int totalNQueens(int n) {
// Note: The Solution object is instantiated only once.
if(n<1) return 0;
totalnum = upperlim = 0;
for(int i = 0; i<n; i++)
upperlim = upperlim<<1 |1;
test(0,0,0);
return totalnum;
}
和普通算法一样,这是一个递归过程,程序一行一行地寻找可以放皇后的地方。过程带三个参数,row、ld和rd,分别表示在纵列和两个对角线方向的限制条件下这一行的哪些地方不能放。
我们以6x6的棋盘为例,假设现在已经递归到第四层,前三层放的子已经放好了。row表示已经放的Queen位置,每一个位置用一个1表示。ld表示已经放好的Queen在做对角线上产生的冲突位置。rd表示在右对角线上产生的冲突位置。把它们三个并起来,得到该行所有的禁位,取反后就得到所有可以放的位置(用pos来表示)。pos &(~pos + 1),其结果是取出最右边的那个1。这样,p就表示该行的某个可以放子的位置,把它从pos中移除并递归调用test过程。注意递归调用时三个参数的变化,每个参数都加上了一个禁位,但两个对角线方向的禁位对下一行的影响需要平移一位。最后,如果递归到某个时候发现row=111111了,说明六个皇后全放进去了,解的个数加1。