Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.

算法一
利用permutation中使用swap的思路,可以快速满足列条件的限制。
这样,在检查合法性时,只需要检查是否满足对角线的限制即可。
此算法在leetcode上的实际的执行时间为4ms。
class Solution {
public:
int totalNQueens(int n) {
int sum = 0;
vector<int> solution;
for (int i=0; i<n; i++)
solution.push_back(i);
helper(solution, 0, sum);
return sum;
}
void helper(vector<int> &solution, int start, int &sum) {
if (start == solution.size()) {
++sum;
return;
}
for (int i=start; i<solution.size(); i++) {
swap(solution[i], solution[start]);
if (isValid(solution, start)) {
helper(solution, start+1, sum);
}
swap(solution[i], solution[start]);
}
}
bool isValid(vector<int> &solution, int start) {
for (int i=start-1; i>=0; --i) {
if (start-i == abs(solution[start]-solution[i]))
return false;
}
return true;
}
};
算法二:
基于回溯法。
特点,利用3个数组,分别记录剩下的列,以及由左对角线,右对角线的限制。
这样在回溯时,可以快速确定某个位置,是否可用。
此算法在leetcode上实际执行时间为3ms。
注,这里选择vector<char>,而不是vector<bool>。这是基于性能考虑,如果选择vector<bool>,执行时间会达到8ms。
原因,则是因为stl 对vector<bool>作了比特化的特化,虽说是省了空间,但却是以时间为代价。
class Solution {
public:
int totalNQueens(int n) {
int sum = 0;
vector<int> cl; // column
vector<char> ld(n*2); //left diagonal
vector<char> rd(n*2); // right diagonal
for (int i=0; i<n; i++)
cl.push_back(i);
helper(cl, 0, ld, 0, rd, n, sum);
return sum;
}
void helper(vector<int> &cl, int start_cl, vector<char> &ld, int start_ld, vector<char> &rd, int start_rd, int &sum) {
if (start_cl == cl.size()) {
++sum;
return;
}
for (int i=start_cl; i<cl.size(); i++) {
const int ldi = start_ld + cl[i];
const int rdi = start_rd + cl[i];
if (!ld[ldi] && !rd[rdi]) {
ld[ldi] = rd[rdi] = true;
swap(cl[i], cl[start_cl]);
helper(cl, start_cl+1, ld, start_ld+1, rd, start_rd-1, sum);
swap(cl[i], cl[start_cl]);
ld[ldi] = rd[rdi] = false;
}
}
}
};算法二,与算法一的主要差别是:
算法二用
!ld[ldi] && !rd[rdi]
这一句代替了算法一中isValid() 函数。
原文地址:http://blog.csdn.net/elton_xiao/article/details/43486937