求解八皇后问题

一、实验目的

利用回溯法搜索或爬山法找到八皇后问题的一个可行解。

二、实验内容

有一个 8 × 8 的棋盘,现在要将8个皇后放到棋盘上,满足:对于每一个皇后,在

自己所在的行、列、两个对角线都没有其他皇后。求所有满足的摆放方式。

                             

图2-1 八皇后问题示意图

三、实验方法

(A)爬山法:

经典的爬山算法也称为局部贪婪搜索(Greedy Local Search),其在算法层的原理为:

随机生成初始状态;

探索初始状态的邻域 K,在 K中选择代价最小(或价值最高)的状态;

若此状态代价小于当前,则选择此状态为下一个状态;否则算法停止;

重复(ii)(iii)直至最优或算法停止。

思路:

1. 先初始化皇后位置,使得每一行每一列一个有且仅有一个皇后

2. 计算冲突的皇后数量(计做冲突值),比如同一行、同一列、同一斜线的数量

3. 准备移动皇后,但是往哪移动呢?每一行皇后只能在自己所在行移动,所以只有列会改变

    比如把第一行皇后从(0,1)移动到(0,0),那么整个棋局的冲突值会发生改变(假设冲突值变小了6->5),此时记录为(0,0):5

   然后遍历所有空位,记录移动到此空位时所有皇后的对应冲突值

4. 找到棋盘中所有空位的冲突值最小的位置,随机选择一个冲突值最小空位置,移动所在行皇后此位置,然后重复上一步3的动作,重新计算棋盘上所有皇后冲突值和所有空位冲突值,循环动作3,直到所有皇后的冲突值为0,此时已经找到一组正确的8皇后位置

5.到第四步已经完成了爬山算法,但是爬山算法有个缺点,有可能找到局部最优,而不是全局最优

   以本案为例只找到了一组最佳位置,但事实上有很多组。此时可以随机生成多个初始位置(也就是爬山起点分散多个地方),就可以找到不同的最佳答案了。

图3-1 爬山法运行结果截图

import random, copy, time

"""

解决8皇后问题

初始化

随机生成皇后位置,使其不同列、不同行只有一个

"""

def init():

    # 随机生成皇后位置,使其不同列、不同行只有一个

    status = []

    for r in range(8):

        while len(status) <= 8:

            c = random.randint(0, 7)

            if c not in [mm[1] for mm in status]:

                status.append((r, c))

                break

    return status

"""

遍历所有皇后

计算有冲突的皇后坐标(同一行,同一列,斜边)

计算整个棋盘冲突的数量

假设初始化传入皇后位置:

[(0, 3), (1, 6), (2, 7), (3, 0), (4, 2), (5, 1), (6, 4), (7, 5)]

"""

def conflict(status):

    num = 0  # 存储冲突数量

    conflict_chess = []

    for pos in status:

        for other_pos in status:

            if pos == other_pos or pos in conflict_chess:

                continue

            elif pos[0] == other_pos[0] or pos[1] == other_pos[1] or abs(pos[0] - other_pos[0]) == abs(

                    pos[1] - other_pos[1]):

                num += 1

                conflict_chess.append(pos)

    return num, conflict_chess

"""

遍历所有空位

计算当行的皇后移动到此空位时整个棋盘的冲突值

会得出8*8-8 = 56个冲突值

也就是56种移动方法

选择冲突值最小的一种进行移动

"""

def move_chess(status):

    empty_pos = {}  # 用字典保存所有空位冲突值

    for r in range(8):

        for c in range(8):

            if (r, c) not in status:

                new_status = copy.deepcopy(status)

                new_status[r] = (r, c)

                empty_pos[(r, c)] = conflict(new_status)[0]

            else:

                continue

    return empty_pos

"""

循环获取冲突数量

若数量>1,执行move_chess

指导冲突数量=0,此时寻找到最佳位置

"""

def climbing(status):

    # 获取当前皇后位置的冲突值

    conflict_num = conflict(status)[0]

    # 设置循环次数,避免一直循环,冲突值一直无法降到最低0时,自动跳出循环

    # 设置移动皇后500次,如果找不到正确位置就重新初始化皇后位置

    loop_cnt = 0

    while conflict_num != 0 and loop_cnt < 500:

        # 获取所有空位冲突值

        empty_pos = move_chess(status)

        min_value = min(empty_pos.values())

        # 获取最小冲突值对应的key 即坐标pos

        min_pos_ls = []

        for k, v in empty_pos.items():

            # print(v, min_value)

            if v == min_value and (k not in min_pos_ls):

                min_pos_ls.append(k)

        # print(min_pos_ls, min_value)

        # print(status)

        # 随机取一个空位点,与当前同一行皇后交换位置,然后计算所有空位置的冲突值和当前棋局内皇后自身冲突值

        i = random.randint(0, len(min_pos_ls) - 1)

        status[min_pos_ls[i][0]] = min_pos_ls[i]

        conflict_num = conflict(status)[0]

        loop_cnt += 1

    return status, loop_cnt

if __name__ == '__main__':

    # 这一个随机数会导致一直找不到最高点

    # status = [(0, 0), (1, 2), (2, 4), (3, 3), (4, 1), (5, 5), (6, 7), (7, 6)]

    # climbing(status)

    """

    生成随机位置,迭代600次尽可能多的找出八皇后不同位置

    """

    start = time.time()

    all_pos = []

    for i in range(600):

        status = init()

        # 设置loop_cnt防止一直陷入死循环无法找到最佳点

        # 如果一直找不到就跳出来并且重新生成初始位置

        status, loop_cnt = climbing(status)

        # print(loop_cnt)

        if loop_cnt == 500:

            continue

        elif status not in all_pos:

            all_pos.append(status)

    end = time.time()

    print("一共找到{}组八皇后位置,共耗时{}s".format(len(all_pos), end - start))

    for pos in all_pos:

        print(pos)

回溯法:

  1. Queen_set 函数接受一个参数 n,表示已经放置的皇后数量。
  2. queen_col_loc 列表用于存储皇后的列位置。
  3. 如果 n 等于 8,表示已经成功放置了八个皇后。在这种情况下,函数通过显示皇后的位置来打印解决方案。
  4. 调用 plot_chess 函数绘制当前的皇后摆放方案。
  5. 递增方案数 num 的值。
  6. 返回函数。
  7. 否则,循环遍历当前行的每个位置。
  8. 检查当前位置是否可以放置皇后,调用 check 函数进行检测。
  9. 如果可以放置皇后,将当前位置添加到 queen_list 列表中。
  10. 递归调用 Queen_set 函数放置下一个皇后。
  11. 回溯,尝试当前行的其他皇后摆放方法,从 queen_list 列表中移除最后一个元素。
  12. check 函数用于检测皇后的位置是否合法。
  13. 如果是第一行,直接返回 True。
  14. 否则,循环遍历之前的每一行。
  15. 检查当前位置是否与之前的皇后所在的列有冲突。
  16. 检查当前位置是否与之前的皇后所在的主对角线和副对角线有冲突。
  17. 如果有任何冲突,返回 False。
  18. 如果通过了所有检测,返回 True。
  19. plot_chess 函数用于绘制棋盘并保存求解结果。
  20. 创建一个大小为 8x8 的全零数组 map
  21. 遍历每一行,将皇后所在的列位置设为 1。
  22. 创建一个颜色映射 cmap,用于绘制棋盘。
  23. 使用 plt.imshow 函数绘制棋盘。
  24. 设置标题和刻度。
  25. 保存绘制的棋盘图像。
  26. 初始化 queen_list 列表为空。
  27. 初始化当前方案数 num 为 1。
  28. 调用 Queen_set 函数,从第一行开始放置皇后。

图3-1 回溯法解决八皇后问题运行结果

目录:

代码段一:导包

代码段二:函数定义

代码段三:调用运行

导包

import numpy as np

import matplotlib

import matplotlib.pyplot as plt

#设定中文字符集,解决绘图时中文乱码问题

matplotlib.rcParams['font.sans-serif'] = ['SimHei']

函数定义

#放置函数,参数为已放置的皇后数量

def Queen_set(n):

    global num

    global queen_list

    queen_col_loc=[i+1 for i in queen_list]

    #方案可行

    if n==8:

        print("第"+str(num)+"种:",(1,queen_col_loc[0]),(2,queen_col_loc[1]),(3,queen_col_loc[2]),(4,queen_col_loc[3])

        ,(5,queen_col_loc[4]),(6,queen_col_loc[5]),(7,queen_col_loc[6]),(8,queen_col_loc[7]))

        #绘制当前的皇后摆放方案

        plot_chess(queen_list)

        num+=1

        return

    else:

        #检查当前行哪一个位置可以放置

        for i in range(8):

            if check(n,i):

                queen_list.append(i)#在当前位置放置皇后

                Queen_set(n+1)#递归放置下一个皇后

                queen_list.pop()#回溯,尝试当前行的其他皇后摆放方法

#检测,传入参数为皇后摆放的位置

def check(row,col):

    if row==0:

        return True

    else:

        #检测列是否与之前摆放的皇后有冲突

        for i in range(row):

            if col==queen_list[i]:

                return False

            #检测对角线是否有冲突,分为主对角线和副对角线,满足直线方程x+y=n 和x-y=n

            elif i+queen_list[i]==row+col or i-queen_list[i]==row-col:

                return False

        return True

    

#绘制棋盘并保存求解结果

def plot_chess(result):

    global num

    map=np.zeros((8,8))

    for i in range(8):

        map[i,result[i]]=1

    cmap = matplotlib.colors.LinearSegmentedColormap.from_list('my_camp', ['white', 'black'], 2)

    plt.imshow(map, cmap=cmap)

    plt.title("第" + str(num) + "种解法", fontsize=16)

    plt.xticks([])

    plt.yticks([])

    plt.savefig('C:/Users/14767/Desktop/expriment/'+str(num)+'.png') #保存图片的路径,自行修改

调用运行

#从第一行开始逐行放置皇后,将皇后的列坐标放入列表中

queen_list=[]

#当前的方案数

num=1

Queen_set(0)

图3-2 八皇后问题解法可视化部分结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/138800.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果10月24日推送iOS 17.1:修复iPhone 12辐射超标问题 信号会更差

前段时间在iPhone 15系列发布的当天&#xff0c;法国突然宣布iPhone 12不能在该国销售&#xff0c;理由是iPhone 12超过了当地无线电频率暴露的法定范围。 根据法国监管机构ANFR(国家频率管理局)发布的最新消息&#xff0c;苹果将会在10月24日推送iOS 17.1正式版&#xff0c;届…

lenovo联想笔记本ThinkPad系列T15p或P15v Gen3(21DA,21DB,21D8,21D9)原厂Win11系统镜像

下载链接&#xff1a;https://pan.baidu.com/s/1V4UXFhYZUNy2ZQ8u4x1AFg?pwdqz0s 系统自带指纹驱动、人脸识别驱动、显卡、声卡等所有驱动、出厂主题壁纸、Office办公软件、Lenovo联想电脑管家等预装程序 所需要工具&#xff1a;32G或以上的U盘 文件格式&#xff1a;ISO …

使用UniApp实现视频数组自动下载与播放功能:一步步指导

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Python+高光谱数据预处理-机器学习-深度学习-图像分类-参数回归

涵盖高光谱遥感数据处理的基础、python开发基础、机器学习和应用实践。重点解释高光谱数据处理所涉及的基本概念和理论&#xff0c;旨在帮助学员深入理解科学原理。结合Python编程工具&#xff0c;专注于解决高光谱数据读取、数据预处理、高光谱数据机器学习等技术难题&#xf…

PC电脑 VMware安装的linux CentOs7如何扩容磁盘?

一、VM中进行扩容设置 必须要关闭当前CentOS&#xff0c;不然扩展按钮是灰色的。 输入值必须大于当前磁盘容量。然后点击扩展&#xff0c;等待扩展完成会提示一个弹框&#xff0c;点击确定&#xff0c;继续确定。 二、操作CentOS扩容——磁盘分区 第一步设置完成。那就启动 …

java springboot VUE粮食经销系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE 粮食经销系统是一套完善的完整信息管理类型系统&#xff0c;结合springboot框架和VUE完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09; &#xff0c;系统具有完整的源代码和数…

【扩散模型从原理到实战】Chapter2 Hugging Face简介

文章目录 Hugging Face的核心功能介绍Hugging Face开源库Hugging Face开源库Gradio工具介绍参考资料 Hugging Face是机器学习从业者协作和交流的平台&#xff0c;成立于2016年&#xff0c;在纽约和巴黎设有办事处&#xff0c;团队成员来自世界各地&#xff0c;远程办公。 致力于…

KNN-近邻算法 及 模型的选择与调优(facebook签到地点预测)

什么是K-近邻算法&#xff08;K Nearest Neighbors&#xff09; 1、K-近邻算法(KNN) 1.1 定义 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别&#xff0c;则该样本也属于这个类别。 来源&#xff1a;KNN算法最早是由Cover和Hart提…

微信小程序--数字化会议OA系统之首页搭建

一、Flex弹性布局 布局的传统解决方案&#xff0c;基于盒状模型&#xff0c;依赖 display属性 position属性 float属性。它对于那些特殊布局非常不方便&#xff0c;比如&#xff0c;垂直居中就不容易实现。 2009年&#xff0c;W3C提出了一种新的方案—-Flex布局&#xff0c;可…

BUUCTF-做题记录

很久没做题了&#xff0c;还是随便来水一水吧&#xff0c;之前都在学别的。 目录 [INSHack2017]remote-multimedia-controller[INSHack2017]hiding-in-plain-sight[QCTF2018]X-man-Keyword[BSidesSF2019]diskimage[2022红包题]虎年大吉[WMCTF2020]行为艺术[MRCTF2020]寻找xxx[…

FPGA project : flash_secter_erase

flash的指定扇区擦除实验。 先发写指令&#xff0c;再进入写锁存周期等待500ns&#xff0c;进入写扇区擦除指令&#xff0c;然后写扇区地址&#xff0c;页地址&#xff0c;字节地址。即可完成扇区擦除。 模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a; module…

Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载

另一个完全不同的redis图形化界面教程链接&#xff08;带安装包&#xff09;&#xff1a; Redis 最流行的图形化界面下载及使用超详细教程&#xff08;带安装包&#xff09;&#xff01; redis windows客户端下载_dream_ready的博客-CSDN博客 redis图形化界面的压缩包&#xff…