回溯法求解N皇后问题

声明:此题为个人方法,仅供参考,如有更简便的方法,欢迎评论区讨论

问题描述:

在一个n*n的棋盘中,我们需要放置n个皇后,使得这n个皇后满足:任意两个都不在同一行,同一列,同一对角线。求解出所有的放置方法。

思路:

这是一个棋盘,这里我们很明显就能想到要用一个二维数组来代表棋盘,当放置一个了皇后,我们就要依条件更新棋盘的元素,这里我们初始化棋盘的初始值为0,如果放置了皇后,依据其皇后的攻击范围来更新棋盘,那么我们又怎么来更新其攻击范围呢?这里我们要设置一个date_attack函数来更新棋盘元素,其条件是要满足在8个方向上,这里我们就可以用两个以为数组一 一对应来代表x,y方向上数值变化,而且变化的话在一个方向上最多只能变化7个位置,如果在某一方向没有这么多位置,例如如果我们放在(1,1)这个位置,而往左上方只有一个位置需要修改,这时我们需要设置一个判断条件x和y的坐标同时满足想x>=0 x<8  y>=0 y<8,这样我们修改的位置就只在这个棋盘内啦。 后面开始从第一行第一列开始寻找,如果合适(if attack[x][i] == 0,不在攻击范围),就更新到下一个状态,并递归寻找第二行满足条件的位置,然后继续更新,又寻找下一行的符合的位置,如果到某一行所有位置都不满足条件了,我们就退回到上一状态,然后判断上一状态后面的那个位置,依次类推,所有的位置就可以找出来啦。还有为了能更清楚地看出棋盘的放置方法,我们还可以设置一个二维数组来表示放置的位置,用Q表示皇后放置的位置,"."表示未放置的位置,满足条件的皇后的位置将此处的 "." 更新为"Q",并继续寻找下一行符合的位置,同上操作,不符合又退回到上一状态。

输入:

n = 8

输出:

小伙伴可以自己试试哟

 代码段


import numpy as np
import sys
n = 8                    # 自己输入n的值
counts = []


def date_attack(a, b, attacks):
    x = [-1, 1, 0, 0, -1, 1,- 1, 1]            #代表8个方向
    y = [0, 0, -1, 1, -1, -1, 1, 1]
    attacks[a][b] = 1
    for i in range(n):
        for j in range(8):                     #更新8个方向
            dx = a + i*x[j]
            dy = b + i*y[j]
            if dx >= 0 and dx < n and dy >= 0 and dy < n:      #满足条件即可更新
                attacks[dx,dy]=1


def backtrack(k, attacks, queens):                  #回溯法进行求解
    if k == n:                                      #达到了最后一行即可输出
        solve = np.zeros(shape=(n, n))
        solve = queens.copy()
        print(solve)
        counts.append(1)
    if k < n:                                     # 未达到最后一行还需继续寻找
        for i in range(n):                        # 找每一行的8个位置
            if attacks[k][i] == 0:                # 不在攻击范围内
                temp = np.zeros(shape=(n, n))
                temp = attacks.copy()
                queens[k][i] = "Q"
                date_attack(k, i, attacks)        #更新棋盘
                backtrack(k+1, attacks, queens)   #寻找下一行满足条件的位置 
                attacks = temp
                queens[k][i] = "."
     


print("\n*************\n")
sys.setrecursionlimit(1000000)
attack = np.array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]])
queen = np.array([[".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."], [".", ".", ".", ".", ".", ".", ".", "."]])
backtrack(0, attack, queen)
print("{}种".format(len(counts)))             #多少种放置方法
print("\n*************\n")

最后,点个关注点个赞再走吧,谢谢大家

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值