经典算法值n后问题,
这题题给你一个n*n的棋盘,问你放置n个皇后共有多少种不用的放置方法,
在任意一个皇后所在位置的水平、竖直、以及45度斜线上都不能出现皇后的棋子
这是一个典型的回溯法框架,并且也是很简单的一个回溯法框架,比这个更简单的就只有字符串全排列问题了。
这题使用深度优先遍历的回溯法解决,每一行只放一个皇后,每一列只放一个皇后,如何判断某个皇后是否和前面已经放置的皇后斜线冲突呢,使用abs(a-b)==abs(c-d),ac,bd分别为参与判断的两个皇后的横纵坐标,只要这个等式成立则这两个皇后一定斜线冲突
使用一个数组存储,数组的下标表示行数,数组存储的值表示列数,通过交换数组每个值的位置就能实现n皇后问题的全排列的寻找
n皇后问题简单易懂算法框架:
大体思路是对于数组list的第t个位置,表示第t层,其值表示这一行的皇后所在的列数,这里假设取list[t]为这一行的列数,当取定这一行的列数后把list[t]和list[a]交换位置,那么t+1~n(n为list长度)就是表示下一层皇后可供选择的列数
如何判断list[a]是否可取呢,只需要判断llist[a]和前面已经确定的皇后位置是否斜线冲突就行了,也就是abs(a-b)==abs(c-d),ac,bd分别为参与判断的两个皇后的横纵坐标
public:
bool check(vector<int> list, int t)
{
for(int i = 0; i < t; i++)
{
if(abs(i - t) == abs(list[i] - list[t])) return false;
}
returntrue;
}
void p(vector<int> list, int t,int& count)
{
if(t == list.size()) {
count++;return; }
for(int i = t; i < list.size(); i++)
{
swap(list[i],list[t]);
if(check(list, t)) p(list, t+1, count);
swap(list[i],list[t]);
}
}
int totalNQueens(int n) {
vector<int>list(n, 0); int count = 0;
for(int i = 0; i < list.size(); list[i] = i,i++);
p(list,0, count);
returncount;
}
};
下面是n皇后问题的最高效率算法:
基本思路跟上面那一个很想,不同的地方是当确定一个皇后的位置后,假设确定位置为t,则将位置t行列之和对应的flag位置设定为1,将t行列之差对应的flag位置设定为1,将t列数相同的flag设置为1,之后再找皇后的时候只需要判断flag[i]&& !flag[row + i +n] && !flag[4* n + row - i])就行了,flag[4*n +row - i])前面加上一个4*n是因为行列之和最大为4*n
class Solution {
public:
inttotalNQueens(int n) {
boolflag[5 * n] ={ false };
int num= 0;
dfs(num, flag, 0, n);
returnnum;
}
void dfs(int& num, bool* flag, int row, int n) {
if (row == n) {
++num;
return;
}
for (int i = 0; i<n; i++) {
if(!flag[i]&& !flag[row + i + n] && !flag[4 * n + row - i]) {
flag[i] = 1;
flag[row + i + n] = 1;
flag[4 * n + row - i] = 1;
dfs(num, flag, row + 1, n);
flag[i] = 0;
flag[row + i + n] = 0;
flag[4 * n + row - i] = 0;
}
}
}
};