N皇后问题

79 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

在学习算法时候,经常遇到一些经典问题,比如含骆驼问题,比如N皇后问题。

汉诺塔复习 三根金刚石柱子,在一根柱子上从下往上按照大小顺序放金圆盘。并且把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

整个问题内层就是一个暴力递归问题。

比如我们点光源一个递归方法,里面包括几块原配,和三个柱子,当盘中只有一个时候,一次就能直接成功,当盘中等于两个时候,需要一定两次。那么倒过来想,我们想把第n个盘移动到另外一个柱子,只需要考虑把他上面的n-1个盘移动到非目标柱子,而要把n-1个盘中移动又需要...

所以整个过程其实就是递归。

image.png

同理,N皇后看上去困难,其实底层也是递归问题。

皇后的走法是:可以横直斜走,格数不限。因此要求皇后彼此之间不能相互攻击,等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上。那么我们可以用一个数字来标识位置,如果被标记,代表不能走。

假设我们现在有5行5列,模拟一下n皇后

image.png

当皇后被放在num[0][0]的位置的时候,对应的num[0][n]和num[n][0]以及num[n][n]不能再放皇后了。所以第二行可以摆放位置是num[1][3],num[1][4],num[1][2]。

假设我们选中num[1][2]

image.png

结果如图,灰色代表不可选。

可以发现这种情况只有唯一解,记录,然后回溯1,假设我们选中num[1][3]

image.png

记录有解情况,继续回溯,假设选中num[1][4]

image.png

然后回溯2,第一个n皇后位置选中Num[0][1] 。。。。

怎么判断在同一对角线?

假设有两个皇后被放置在(i,j)和(k,l)的位置上,明显,当且仅当|i-k|=|j-l| 时,两个皇后才在同一条对角线上。

  • 先从首位开始检查,如果当前不能放置皇后,接着检查该行第二个位置,依次检查下去,直到在该行找到一个可以放置一个皇后的地方,然后保存当前状态,转到下一行。
  • 如果检查了该行所有的位置后均不能放置皇后,说明上一行皇后放置的位置无法让所有的皇后找到自己合适的位置,因此就要回溯到上一行,重新检查该皇后位置后面的位置。

我们可以类比全排列问题。

image.png

n皇后也可以排成树(关于回溯模板查看这个链接) 和递归很相似的回溯 - 掘金 (juejin.cn)

单层尝试逻辑: 外层for控制换行,内层控制列,每一次都是新的行开始,如果当前位置判断合法(可以放),那么就修改当前数组值,并且递归调用下一行,然后对本行进行回溯

怎么判断合法? 就是判断我们数组是不是有皇后了,或者是不是和其他皇后在同一对角线。

image.png

递归怎么写? 如果当前位置在最后一行了,就返回一个结果,否则对列进行遍历,判断当前第i行皇后在第j列,会不会和之前的皇后同行,同列,同斜线?如果不同,就修改当前数组值,并且重新调用递归方法(整个递归方法就是第i+1行的皇后怎么摆了。)

image.png