n皇后问题解决思路,代码,代码解读以及回溯法的举一反三

1 篇文章 0 订阅
1 篇文章 0 订阅

N皇后问题解决思路

问题:n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击(即同行同列且同一斜边不能出现2个皇后)。

前提:n>3 (否则无解)

思路:已知n<=3无解,那就选最简单的4*4表格

如果第一个格子内放一个皇后那么第一行,第一列,全部都不能再放皇后且与1.1斜边对应的2,2   3,3     4,4都不能放皇后

再2,3再放一个皇后

此时无解在试2,4放一个皇后

显然3,2和4,3在同一斜边上所以第一行放第一列是无解的,所以在第一行第二列上放

第二行只能在2,4的位置放,之后就可以直接看出答案。如下图即

在方格为4的表格里,前一半列数(2)的解为1个那么,水平翻转就是剩下的解,如下图

此时我们的解题思路大概就出来了。

需要一个位置记录黑名单即 摆放过皇后的位置,其同行同列 同一斜边都不能再放。

需要一个记录皇后位置集,

需要一个计数器。

如果我们记录皇后位置的集合用一个N个数字的数组 第一个数字表示第一行第二个数字表示第二行那么。黑名单就可以只记录列和斜边

我们发现一个位置的斜边左上和右下相减是同一个数字,右上和左下相加数值相等,那么我门再用一个列的数组和两个斜边的数组记录黑名单。

贴代码

public class Queen {
    private int[] column; //黑名单1,列已占用
    private int[] rup; //黑名单2,左上右下
    private int[] lup; //黑名单1,
    private int[] queen; //所在对应列的位置
    private int num; //计数器

    public Queen() {
        column = new int[8+1];
        rup = new int[(2*8)+1];
        lup = new int[(2*8)+1];
        for (int i = 1; i <= 8; i++)
            column[i] = 0;
        for (int i = 1; i <= (2*8); i++)
            rup[i] = lup[i] = 0;  //初始定义全部无皇后
        queen = new int[8+1];
    }

    public void backtrack(int i) {
        if (i > 8) {
            showAnswer();
        } else {
            for (int j = 1; j <= 8; j++) {
                if ((column[j] == 0) && (rup[i+j] == 0) && (lup[i-j+8] == 0)) {
                    //若无皇后
                    queen[i] = j; //设定为占用
                    column[j] = rup[i+j] = lup[i-j+8] = 1;
                    backtrack(i+1);  //循环调用
                    column[j] = rup[i+j] = lup[i-j+8] = 0;
                }
            }
        }
    }

    protected void showAnswer() {
        num++;
        System.out.println("\n解答" + num);
        for (int y = 1; y <= 8; y++) {
            for (int x = 1; x <= 8; x++) {
                if(queen[y]==x) {
                    System.out.print("Q");
                } else {
                    System.out.print(".");
                }
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        Queen queen = new Queen();
        queen.backtrack(1);
    }
}

代码解读

如上所说,定义一个列,一个坐上右下(相减是同一个数)和右上左下(相加是同一个数)的黑名单

代码开头初始化几个数组的值,8皇后问题,数组长度都+1是为了后面从1开始,下面的循环都是从1开始,所以这个不必纠结。

然后开始执行主体,主体其实是一个递归,主体后面讲,我们先看出口1,出口1里面是一个解答答案的过程其实就是连个for循环循环输出而已,这里其实已经是答案弄好了。这里也很简单。

但是答案怎么来,看条件,每次i>8说明什么?i是什么?

i可以理解为行数,i大于8说明递归的时候i在第八行 有合适的位置让皇后放,也就是已经有一种解了 。

 

出口2,是for循环里面1-8的位置都不符合放皇后的要求。循环直接循环完。这一种方案是无解的,说明上一层位置不能选这个位置,所以上一层的黑名单位置去除掉,

(理论上这里也应该将queen[i]=0将,queen数组i的位置上置空。但是后面也会重复工作也会重复赋值,所以可以省去这个工作。)

此时的递归的方法走完,跳出来,执行上一层的黑名单置空。然后在上一层下一个位置j+1在进行判断

看递归上两行代码,

i行如果第j个列满足条件可以放皇后条件即使这个坐标的列没有被加入黑名单,坐上右下的黑名单和右上左下的黑名单也没有它。(条件:

这个递归在for循环里,其实实际上就是两个for循环循环套用。

温故而知新

这个问题是用回溯法解决的(穷举法暴力破解)。举一反三,以后遇到需要用回溯法解决问题的时候,代码就可以写成这样。用递归解决。递归之前写占位操作(以后进行判断)递归之后写清除操作

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯法是一种通过试错的方式来寻找问题解决方法的算法。在解决n皇后问题时,回溯法可以用来找到所有的合法解。 n皇后问题的目标是将n个皇后放置在一个n×n的棋盘上,使得每个皇后都不会攻击到其他的皇后。这意味着每一行、每一列和每一条斜线上只能有一个皇后。 下面是一个基于回溯法n皇后问题代码实现思路: 1. 首先,我们定义一个递归函数来解决问题。这个函数的输入参数包括当前行数、一个数组来表示每一行皇后的位置,以及一个记录所有解决方案的列表。 2. 在递归函数中,我们对当前行的每一个位置进行尝试。如果当前位置可以放置皇后,我们将其标记为“已使用”,并将其加入到数组中。 3. 然后,我们递归地调用函数来处理下一行。 4. 如果已经处理完了所有的行,说明我们找到了一个解决方案。我们将这个方案加入到解决方案列表中。 5. 如果当前位置无法放置皇后,我们将其标记为“未使用”,并回溯到上一行,继续尝试其他的位置。 6. 当所有的可能性都已经尝试完毕,我们就能得到所有的合法解决方案了。 下面是一个基于回溯法n皇后问题的Python代码实现: ```python class Solution: def solveNQueens(self, n: int) -> List[List[str]]: def backtrack(row, path, res): if row == n: res.append(path[:]) return for col in range(n): if is_valid(row, col, path): path.append(col) backtrack(row+1, path, res) path.pop() def is_valid(row, col, path): for r, c in enumerate(path): if c == col or abs(row-r) == abs(col-c): return False return True res = [] backtrack(0, [], res) return [['.'*col + 'Q' + '.'*(n-col-1) for col in sol] for sol in res] ``` 在这个代码中,我们使用了两个辅助函数:`backtrack`和`is_valid`。`backtrack`函数用于递归地尝试放置皇后,`is_valid`函数用于检查当前位置是否可以放置皇后。 我们首先调用`backtrack`函数来解决n皇后问题。在函数中,我们使用一个`path`数组来记录每一行皇后的位置。在每一行中,我们尝试每一个位置来放置皇后,并递归地处理下一行。如果当前行已经处理完毕,我们就将当前方案加入到结果列表中。 在`is_valid`函数中,我们检查当前位置是否和之前的皇后位置冲突。如果存在冲突,就返回False。否则,返回True。 在最后,我们将结果列表转换为字符串列表来表示棋盘中皇后的位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值