对于N皇后这类问题之前还是很恐惧的 看都看不懂 好复杂。。。 后来慢慢可以理解递归的完整过程
递归的本质是开出分支 一旦一个分支能走到最后一行 那就说明该条分支是符合的一条摆放路径
很多递归的问题也都迎刃而解了
N皇后题目就不叙述了
首先N皇后通过回溯法来解决 N*N大小的棋盘里放N个皇后 至少说明 每行都放了一个,且只有一个
毕竟皇后不能同行同列
从第一行开始, 第一行的每个位置都可以当做摆放第一个皇后的开始。所以通过递归岔开了N个分支。
第m行开始的时候 我们需要满足皇后不能对角线相同 所以一个数组来保存前m-1个皇后的位置
只需要用一维数组保存 数组的下标表示了皇后的纵坐标 数组中的值表示了皇后的横坐标 我们只需要重写一个函数
来判断是不是和之前皇后重行或对角(一定不会重列 ) 假设两个坐标A(x1,y1) B(x2,y2)对角了 则说明
abs(x1-x2)== abs(y1-y2)
所以判断函数的参数有三个 分别是该位置的横纵坐标 已经 之前皇后摆放的坐标
遍历之前皇后坐标并比较
bool isRepeat(int i , int j , vector< int > rand) {
for (int k = 0 ; k < i ; k++) {
if (rand[k] == j || abs(i - k) == abs(j - rand[k]))
return false;
}
return true;
}
递归的本质是开出分支 一旦一个分支能走到最后一行 那就说明该条分支是符合的一条摆放路径
最终累加分支的个数 就得到皇后可以摆放的全部情况
代码如下
int totalNQueens(int n) {
// write your code here
if (n <= 0)
return 0;
vector< int > rand(n , 0);
return getNQueensNum(0 , n , rand);
}
int getNQueensNum(int i , int n , vector< int >& rand) {//递归部分
if ( i == n )//发现满足条件的一条路径
return 1;
int res = 0;//路径总和
for (int j = 0 ; j < n ; j++) {
if (isRepeat(i , j , rand)) {//满足摆放条件才能开辟分支
rand[i] = j;
res += getNQueensNum(i + 1 , n , rand);//开辟分支
}
}
return res;
}
bool isRepeat(int i , int j , vector< int > rand) {
for (int k = 0 ; k < i ; k++) {
if (rand[k] == j || abs(i - k) == abs(j - rand[k]))
return false;
}
return true;
}