题意分析
经典模板题,n皇后问题。给你一张nxn的棋盘。需要往这个棋盘里面放一些棋子。然后需要保证这n个棋子之间不同同行同列和同正反斜线。
也就是下图中在同一条线上面的不能同时放置棋子。
思路分析
好了,我们现在知道题目意思了,我们可以来说说怎么解这题。首先,我们需要知道如何判断两个位置是否满足题目条件。同一行同一列我们知道可以可以使用两个数组来标识。但是如何处理正对角线和反对角线的情况呢?我们根据上面的图可以知道,对于正和反对角线的情况。这两种线的斜率分别为1和-1.假设有两个点在正斜线上,那么
,反斜线同理
。所以我们可以将每个点放入一个数组里面。但是对于正斜线的情况,我们发现可能存在负数的情况,为了防止负数的产生,我们可以给这个和加上一个n保证这个数为正数。
知道怎么判断之后,我们来说一下怎么遍历所有的情况,那就是回溯算法。我们对这个棋盘进行dfs,我们以x坐标作为dfs的起点,一层一层向下进行递归处理,当我们到了某一层的时候,我们枚举这一层放置的位置的y坐标,如果满足条件,则向下进行递归,然后进行回溯即可。
DFS回溯的话可以结合我的这张图进行理解。
写法一 C++版
- 代码如下
- 我们需要枚举出n个棋子的所有的排列。所以空间复杂度为O(n!)
- bool数组需要存储坐标的和,最大需要开到2n,所以空间复杂度为O(n)
class Solution {
public:
/**
*
* @param n int整型 the n
* @return int整型
*/
bool col[16],row[16],pos[30],neg[30];
int ans=0;
void dfs(int x,int n){ // x表示此时的横坐标的位置
// std::cout<<x<<endl;
if(x==n+1){
// 可以成功到达边界,答案累加1
ans++;
return;
}
for(int i=1;i<=n;i++){ // 枚举纵坐标
// 如果选的这个位置在同一行,同一列,同一正斜线和同一反斜线,那么就不符合
//std::cout<<col[i]<<row[x]<<pos[i-x+n]<<neg[i+x]<<endl;
if(col[i]||row[x]||pos[i-x+n]||neg[i+x]) continue;
// 此时在(x,i)位置放一个皇后
col[i]=row[x]=pos[i-x+n]=neg[i+x]=true;
dfs(x+1,n);
// 进行回溯
col[i]=row[x]=pos[i-x+n]=neg[i+x]=false;
}
}
int Nqueen(int n) {
// write code here
memset(pos,false,sizeof(pos));
memset(neg,false,sizeof(neg));
memset(row,false,sizeof(row));
memset(col,false,sizeof(col));
dfs(1,n);
return ans;
}
};写法二 Go语言版
- 代码如下
- 我们需要枚举出n个棋子的所有的排列。所以空间复杂度为O(n!)
- bool数组需要存储坐标的和,最大需要开到2n,所以空间复杂度为O(n)
package main
/**
*
* @param n int整型 the n
* @return int整型
*/
var ans int
func dfs(x, n int,col,row,neg,pos []bool){
if(x==n){ // x表示此时的横坐标的位置
ans+=1
return
}
for i:= 1;i<=n;i++ { // 枚举纵坐标
// 如果选的这个位置在同一行,同一列,同一正斜线和同一反斜线,那么就不符合
if(col[i]||row[x]||pos[i-x+n]||neg[i+x]) {
continue
}else{
col[i]=true
row[x]=true
pos[i-x+n]=true
neg[i+x]=true
// 此时在(x,i)位置放一个皇后
dfs(x+1,n,col,row,neg,pos)
// 进行回溯
col[i]=false
row[x]=false
pos[i-x+n]=false
neg[i+x]=false
}
}
}
func Nqueen( n int ) int {
// write code here
row := make([]bool,n+1)
col := make([]bool,n+1)
pos := make([]bool,2*n+1)
neg := make([]bool,2*n+1)
dfs(0,n,col,row,neg,pos)
return ans;
}
京公网安备 11010502036488号