【回溯算法】n皇后问题(详解 + 详细代码)

9 篇文章 0 订阅
8 篇文章 0 订阅

目录

题目:

 解题思路:

代码来啦!!!


题目:

        按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子

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

        给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

        每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

注:OJ题目链接:力扣:N皇后 

输出示例:

ps:此图来自力扣 

 解题思路:

        1,首先我们以每一行为一个基准,例如我们放置了第一行,那么只能去第二行寻找可以放置皇后的位置,以此类推,直到最后一行,如果到最后一行都能将皇后放置进去,说明这是一个可行的方案,如果不行,则回退【回溯算法:当发现已不满足求解条件时,就“回溯返回,尝试别的路径

        举例(此处想用一个狗头,嘿嘿,补充一句,想知道大家国庆怎么过的,这七天,是谁玩废了,我闭嘴我不说,哈哈哈哈)正经来了,举例举例:

        2,首先一个皇后放在了第一行,那么,它所在的列,以及交叉线都不能放置皇后了,那么我们怎么用状态标识呢,那我们不妨每列,和两个交叉线都用一个集合存放,每列我们好表示,把第一列或者第二列放到集合里说明,这列被用了,那么两个交叉线怎么表示呢?
如图,当皇后放置在(1,2)这个位置:

左上向下的这条斜线:

        它们的位置分别是(0,1),(1,2),(2,3)那么每个坐标里的行坐标减去列坐标,0-1 == 1-2 == 2-3 ==-1,正好是等值。

右上向下的这条斜线:

        它们的位置分别是(0,3),(1,2),(2,1),(3,0),那么每个坐标里的值相加,0+3 == 1+2== 2+1 == 3+0 ==3 ,正好是等值。 

        快看吧,有木有很神奇,你们自己随便找个位置试一下,是不是都有一个等值,并且都不重复,那么我们就把相应的值加入到集合里面,是不是就能标识,是不是这些位置都不能放置皇后了

代码来啦!!!

class pair {
    public int x;
    public int y;

    public pair(int x,int y) {
        this.x = x;
        this.y = y;
    }
}
class Solution {
    public List<List<String>> solveNQueens(int n) {
        //按坐标位置存放所有方案
        List<List<pair>> solutions = new ArrayList<>();
        //存放一种解决方案中的所有皇后的位置
        List<pair> solution = new ArrayList<>();

        nqueensBackTrack(solutions,solution,0,n);

        //把坐标位置转成String
        return transResult(solutions, n);

    }
    public void nqueensBackTrack(List<List<pair>> solutions,List<pair> solution,int curRow,int n) {
        if(curRow==n) {
            List<pair> newS = new ArrayList<>();
            for(pair p : solution) {
                newS.add(p);
            }
            solutions.add(newS);
        }
        //尝试当前行的每一个位置是否可以放置一个皇后
        for(int col = 0;col<n;col++) {
            if(isValid(solution,curRow,col)) {
                //如果可以,在保存当前位置,继续确定下一行皇后的位置
                //直接调用构造函数,内部构造pair,或者调用make_pair
                solution.add(new pair(curRow,col));
                nqueensBackTrack(solutions,solution,curRow+1,n);
                //回溯,删除当前位置,尝试当前行的其他位置
                solution.remove(solution.size()-1);
            }
        }
    }
    //solution:一个解决方案,从第一行开始到当前行的上一行每一行已经放置皇后的点
    boolean isValid(List<pair> solution,int row,int col) {
        //判断当前行尝试的皇后位置是否和前几行的皇后位置有冲突
        //i.second == col :第i个皇后与当前这个点在同一列
        //i.first+i.second == row+col:第i个皇后与当前点在撇上,横坐标+纵坐标值相同
        //i.first-i.second == row+col:第i个皇后与当前点在捺上,横坐标-纵坐标值相同
        for(pair i :solution) {
            if(i.y == col||i.x+i.y==row+col||i.x-i.y==row-col) {
                return false;
            } 
        }
        return true;
    }
    List<List<String>> transResult(List<List<pair>> solutions,int n) {
        List<String> tmp = new ArrayList<>();
        //把每一种解决方案都转换为String形式,最终结果
        List<List<String>> ret = new ArrayList<>();
        for(List<pair> solution:solutions) {
            //n*n char:每行有n个元素,把皇后的位置修改为Q
            List<StringBuilder> solutionString = new ArrayList<>();
            for(int i = 0;i<n;i++) {
                StringBuilder sb = new StringBuilder();
                for(int j = 0;j<n;j++) {
                    sb.append('.');
                }
                solutionString.add(sb);
            }
            for(pair i :solution) {
                solutionString.get(i.x).setCharAt(i.y,'Q');

            }
            List<String> curRet = new ArrayList<>();
            for(StringBuilder sb:solutionString) {
                curRet.add(sb.toString());
            }
            ret.add(curRet);
        }
        return ret;
    }
}

ps:听上去很简单的样子,但还是需要用心看看代码,自己敲着试试看!!!

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙洋静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值