#51N皇后hard

题目描述:

皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/10/12/8-queens.png

上图为 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;
           }
       }
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值