题目描述:
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
思路&代码解释1:
class Solution {//回溯法
//确定那一列是否被皇后占据了
int rows[];
//确定相应的主对角线是否被占据,\:row-col==constant;
int hills[];
//确定相应的副对角线是否被占据,/:row+col==constant;
int dales[];
int n;
//定义输出
List<List<String>> output=new ArrayList<>();
int queens[];//记录皇后每行对应占据的行号
public List<List<String>> solveNQueens(int n) {
this.n=n;
rows=new int[n];
//设置成4*n-1是可以满足row-col的constant数值在2n附近,且都为正数
hills=new int[4*n-1];
dales=new int[2*n-1];
queens=new int[n];
backtrack(0);//抽离出回溯方法
return output;
}
public void backtrack(int row){
for(int col=0;col<n;col++){
if(isNotUdnderAttack(row,col)){
placeQueen(row,col);//放置皇后在row,col位置,并进行攻击位置重置
if(row+1==n)
addSolution();
else
backtrack(row+1);
//移除上次新加入的皇后,进行回溯
removeQueen(row,col);
}
}
}
public void addSolution(){
List<String> solution=new ArrayList<String>();
for(int i=0;i<n;i++){
int col=queens[i];//取出皇后每行所在的列数
StringBuilder sb=new StringBuilder();
for(int j=0;j<col;j++)//进行构造出解决方案
sb.append(".");
sb.append("Q");
for(int j=0;j<n-col-1;j++)
sb.append(".");
solution.add(sb.toString());
}
output.add(solution);
}
public void placeQueen(int row,int col){
queens[row]=col;
rows[col]=1;
hills[row-col+2*n]=1;
dales[row+col]=1;
}
public void removeQueen(int row,int col){
queens[row]=0;
rows[col]=0;
hills[row-col+2*n]=0;
dales[row+col]=0;
}
public boolean isNotUdnderAttack(int row,int col){
int res=rows[col]+hills[row-col+2*n]+dales[row+col];
return res==0;
}
/**
//上面判断位置是否有效的另一种判断方法,可以节省空间
public boolean isNotUnderAttack(int row ,int col){
for (int i = 0; i < row; ++i)
//叼就叼在判断对角线冲突非常简便,因为当两个点(或者皇后)在同一条对角线上,
//那么二者的横坐标差的绝对值,等于纵坐标差的绝对值
//利用这条性质,可以快速的判断冲突,
if (col == queens[i] || Math.abs(row - i) == Math.abs(col - queens[i]))
return false;
return true;
}
*/
}
思路&代码解释2:
有问题,没调试出来,用的是二维数组构造棋盘,不被攻击位置为0,攻击位置为1;有问题!!!!!
class Solution {//回溯法
int[][] mark;//标记棋盘是否可以放置皇后的二维数组
int queens[];//记录每个皇后的每行位置
List<List<String>> output=new ArrayList<>();//先建立一个存储最终结果的数组
int n;
int[][] tem;
public List<List<String>> solveNQueens(int n) {
this.n=n;
mark=new int[n][n];
queens=new int[n];
tem=new int[n][n];
backtrack(0);
return output;
}
public void backtrack(int row){
if(row+1==n){
addSolution();
return;
}
for(int col=0;col<n;col++){
if(mark[row][col]==0){
tem=mark;
placeQueen(row,col);//放置皇后在row,col位置,并进行攻击位置重置
backtrack(row+1);
//移除上次新加入的皇后,进行回溯
mark=tem;
queens[row]=0;
}
}
}
public void addSolution(){
List<String> solution=new ArrayList<String>();
for(int i=0;i<n;i++){
int col=queens[i];//取出皇后每行所在的列数
StringBuilder sb=new StringBuilder();
for(int j=0;j<col;j++)//进行构造出解决方案
sb.append(".");
sb.append("Q");
for(int j=0;j<n-col-1;j++)
sb.append(".");
solution.add(sb.toString());
}
output.add(solution);
}
public void placeQueen(int x,int y){//将x,y位置放置皇后,mark二维数组表示一张棋盘
queens[x]=y;
int dx[]={-1,1,0,0,-1,-1,1,1};//方向数组,上下左右...等八个方向
int dy[]={0,0,-1,1,-1,1,-1,1};
mark[x][y]=1;//放置皇后,进行标记
for(int i=1;i<n;i++){//八个方向,每个方向延伸至n-1位置
for(int j=0;j<8;j++){
int new_x=x+i*dx[j];
int new_y=y+i*dy[j];
if(new_x>=0&&new_x<n&&new_y>=0&&new_y<n)//检查新的位置是否还在棋盘内
mark[new_x][new_y]=1;
}
}
}
}