N皇后问题的深度优先搜索实现(基于Python)

N皇后问题的深度优先搜索实现(基于Python)

其实是人工智能大作业中的一部分啦~
解决方法就是很朴素的盲目搜索

算法简介

1.盲目搜索——DFS

DFS(Deep First Search),即深度优先搜索算法。将棋盘视为N行N列的矩阵(以二维列表的方式存储),从第1行开始放置皇后,然后第2行、第3行、…、第i行(i <= N),如果i=N,则所有皇后放置完毕;如果i != N且棋盘上已经没有可以放置皇后的位置,则当前放置方案不可行,回溯至上一个状态,寻找新的分支并继续求解。

2.回溯算法

回溯算法的核心是,当待解决的问题有一个最终的结果时(所有皇后放置完毕或者没有位置可以放置剩余的皇后),回溯当前状态,进入另一个分支,继续求解,直到搜索树遍历完毕。


算法设计与描述

1.State类
  • 成员变量说明:
    N:棋盘大小N*N,N个皇后(整数)
    current_grid: 当前棋盘状态(二维列表)
    New_Q: 最新放置的皇后的位置(二维元组)
    parent_state: 父状态(State类对象)
    deep: 搜索进行的深度,即已放置的皇后的数量(整数)
  • 成员函数说明:
    (1)init(self, parent_state, Q_ij, NQ)
    根据传入的父状态、最新放置皇后的位置、N,进行相应的赋值;更新棋盘的空间状态(update_grid函数)
    (2)update_grid(self)
    将棋盘中皇后的位置赋值为10;将皇后的可攻击范围的棋盘位置赋值为1;返回赋值结束后的棋盘状态(二维列表)
    (3)show_grid(self)
    打印当前棋盘状态;值为10的位置为皇后的位置,其余位置为空
2.get_extended_space_list(current_state, NQ)
  • 参数说明:
    current_state: 当前状态(State类对象)
    NQ:N皇后的N
  • 返回值说明:
    res_list: 还能用来放置皇后的位置(二维元组)
  • 程序框图
    在这里插入图片描述
3. 主程序
  • 改变NQ的值以求解其他N皇后问题
  • 程序框图
    在这里插入图片描述

实现代码

import copy as cp
global count

count = 0

class State:
    N = 8
    current_grid = []  # 当前棋盘
    NewQ = (-1, -1)  # 当前棋子的位置
    parent_state = None  # 父状态
    deep = 0  # 状态深度

    def __init__(self, parent_state, Q_ij, NQ):
        if parent_state is None:
            self.N = NQ
            self.NewQ = Q_ij  # 当前棋子的位置
            self.parent_state = parent_state
            self.deep = 0
            self.current_grid = [[0 for i in range(self.N)] for j in range(self.N)]  # 当前棋盘
        else:
            self.N = NQ
            self.NewQ = Q_ij  # 当前棋子的位置
            self.parent_state = parent_state
            self.deep = self.parent_state.deep + 1
            self.current_grid = self.update_grid()  # 当前棋盘

    # 根据父状态和当前棋子位置,对当前棋盘的空余位置情况作更新
    def update_grid(self):
        line = self.NewQ[0]
        column = self.NewQ[1]
        if line != -1 and column != -1:
            if self.parent_state is None:
                next_grid = [[0 for i in range(self.N)] for j in range(self.N)]
                next_grid[line][column] = 10
            else:
                next_grid = cp.deepcopy(self.parent_state.current_grid)
                next_grid[line][column] = 10
                # 向上占位
                while line > 0:
                    next_grid[line - 1][column] = 1
                    line = line - 1
                line = self.NewQ[0]
                # 向下占位
                while line < self.N - 1:
                    next_grid[line + 1][column] = 1
                    line = line + 1
                line = self.NewQ[0]
                # 向左占位
                while column > 0:
                    next_grid[line][column - 1] = 1
                    column = column - 1
                column = self.NewQ[1]
                # 向右占位
                while column < self.N - 1:
                    next_grid[line][column + 1] = 1
                    column = column + 1
                column = self.NewQ[1]
                # 向左下角占位
                while column > 0 and line < self.N - 1:
                    next_grid[line + 1][column - 1] = 1
                    column = column - 1
                    line = line + 1
                line = self.NewQ[0]
                column = self.NewQ[1]
                # 向右下角占位
                while column < self.N - 1 and line < self.N - 1:
                    next_grid[line + 1][column + 1] = 1
                    column = column + 1
                    line = line + 1
            return next_grid
        else:
            print("no solution here!")
            return None

    # 打印当前棋盘
    def show_grid(self):
        for i in range(len(self.current_grid)):
            print("|", end="")
            for j in range(len(self.current_grid[i])):
                if self.current_grid[i][j] == 1:
                    print(" ", end=" ")
                else:
                    print("Q", end=" ")
            print("|")
        print("*****-----------------*****\n*****-----------------*****")


def get_extended_space_list(current_state, NQ):
    global count
    res_list = []
    if current_state.parent_state is None:
        line = 0
        for column in range(len(current_state.current_grid[line])):
            if current_state.current_grid[line][column] == 0:
                res_list.append((line, column))
    else:
        line = current_state.NewQ[0] + 1
        column = 0
        while column <= NQ - 1:
            count += 1
            if current_state.current_grid[line][column] >= 1:
                column = column + 1
            else:
                res_list.append((line, column))
                column = column + 1
    return res_list


NQ = 10
start_grid = [[0 for i in range(NQ)] for j in range(NQ)]
start_Q_ij = (-1, -1)
start_state = State(None, start_Q_ij, NQ)
start_space = get_extended_space_list(start_state, NQ)
open_list = []
solution = 0  # 记录成功结果的数量
search_sum = 0  # 记录找到单个结果时所用搜索次数
sum_in_total = 0  # 记录所有成功结果的搜索次数和
for i in range(len(start_space)):
    new = State(start_state, start_space[i], NQ)
    open_list.insert(0, new)
while len(open_list) != 0:
    # search_sum = search_sum + 1
    # print(len(open_list))
    current_state = open_list.pop(0)
    if current_state.deep == NQ:  # 如果当前状态的deep为NQ,说明所有棋子都放置完毕,即得到一种解
        solution = solution + 1
        print("this is solution No.", solution, sep="")
        current_state.show_grid()
        sum_in_total = sum_in_total + search_sum
        print("search_sum = ", search_sum)
        search_sum = 0
        continue
    new_space = get_extended_space_list(current_state, NQ)  # 得到可放置棋子的位置坐标列表
    for i in range(len(new_space)):
        search_sum += 1
        new_state = State(current_state, new_space[i], NQ)
        open_list.insert(0, new_state)

print("\n\n******************\nThere are ", solution, " solutions to ", NQ, "-Queens problem in total!", sep="")
# print("平均搜索次数为", sum_in_total / solution)
print("平均搜索次数为%.3f" % (count / solution))
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值