实验8 搜索技术

news2025/3/15 10:10:00

实验8 搜索技术

一、实验目的
(1)掌握搜索技术的相关理论,能根据实际情况选取合适的搜索方法;
(2)进一步熟悉盲目搜索技术,掌握其在搜索过程中的优缺点;
(3)掌握启发式搜索的思想,能针对实际问题选取合适的评价函数;
(4)掌握问题归约的解决问题的思想,掌握与或图的搜索技术并能应用;
(5)深入理解博弈树搜索方法,并能应用于对弈类问题;
(6)根据自身情况,能选择合适的编程语言,实现启发式搜索、博弈树搜索方法、α-β剪枝算法,并能应用于实际AI问题。

二、实验内容
选择一种编程语言(最好为python或java),编程实现下面题目要求。
1、八数码难题
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格可用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局,找到一种启发式移动方法,实现从初始布局到目标布局的转变,并与实验7 的盲目移动方法对比。
在这里插入图片描述

1、需求分析
在一个3×3的九宫格棋盘上,摆有8个正方形方块,每一个方块都标有1~8中的某一个数字。棋盘中留有一个空格,要求按照每次只能将与空格相邻的方块与空格交换的原则,将任意摆放的数码盘(初始状态)逐步摆成某种给定的数码盘的排列方式(目标状态)。

2、数据结构、功能模块设计与说明
运用启发式搜索,利用问题拥有启发信息引导搜索,以达到减小搜索范围、降低问题复杂度的目的。在启发式搜索过程中,要对Open表进行排序,这就要有一种方法来计算待扩展结点有希望通向目标结点的不同程度,人们总是希望找到最有可能通向目标结点的待扩展结点优先扩展。一种最常用的方法是定义一个评价函数对各个结点进行计算,其目的就是用来估算出“有希望”的结点。用f来标记评价函数,用f(n)表示结点n的评价函数值,并用f来排列等待扩展的结点,然后选择具有最小f值的结点作为下一个要扩展的结点。
A*算法是一种有序搜索算法,其特点在于对评价函数的定义上。这个评估函数f使得在任意结点上其函数值f(n)能估算出结点S到结点n的最小代价路径的代价与从节点n到某一目标节点的最小代价路径的代价的总和,也就是说f(n)是约束通过结点n的一条最小代价路径的代价的估计。

3、核心代码(不要将全部代码贴在报告上)与测试结果说明
核心代码:
定义A*算法

def A_start(start, end, distance_fn, generate_child_fn, time_limit=10):
    # 创建起始状态结点和目标状态结点对象,并分别计算其哈希值
    root = State(0, 0, start, hash(str(BLOCK)), None)
    end_state = State(0, 0, end, hash(str(GOAL)), None)
    # 检查起始状态是否就是目标状态,如果是,则直接输出提示信息
    if root == end_state:
        print("start == end !")
    # 将起始状态结点加入到OPEN表中,并对OPEN表进行堆化操作
    OPEN.append(root)
    heapq.heapify(OPEN)
    # 创建一个哈希集合,用于存储已经生成的状态结点的哈希值,并将起始状态结点的哈希值添加到集合中
    node_hash_set = set()
    node_hash_set.add(root.hash_value)
    # 记录算法开始的时间
    start_time = datetime.datetime.now()
    # 进入主循环,直到OPEN表为空(搜索完成)或达到时间限制
    while len(OPEN) != 0:
        top = heapq.heappop(OPEN)
        # 如果当前结点就是目标状态结点,则直接输出路径
        if top == end_state:
            return print_path(top)
        # 产生孩子节点,孩子节点加入OPEN表
        generate_child_fn(cur_node=top, end_node=end_state, hash_set=node_hash_set,
                          open_table=OPEN, dis_fn=distance_fn)
        # 记录当前时间
        cur_time = datetime.datetime.now()
        # 超时处理,如果运行时间超过了设定的时间限制,则输出超时提示信息并返回
        if (cur_time - start_time).seconds > time_limit:
            print("Time running out, break !")
            print("Number of nodes:", SUM_NODE_NUM)
            return -1
    # 如果循环结束时OPEN表为空,则表示没有找到路径,输出提示信息并返回-1
    print("No road !")  # 没有路径
    return -1

定义曼哈顿距离计算函数

def manhattan_dis(cur_node, end_node):  # 定义一个名为manhattan_dis的函数,接受两个参数cur_node(当前结点)和end_node(目标结点)
    # 获取当前结点和目标结点的状态矩阵
    cur_state = cur_node.state
    end_state = end_node.state
    dist = 0
    N = len(cur_state)  # 获取状态矩阵的大小,假设为N
    # 遍历状态矩阵中的每个位置
    for i in range(N):
        for j in range(N):
            # 如果当前结点的值与目标结点的值相等,则跳过当前位置,因为这个位置已经在目标状态中
            if cur_state[i][j] == end_state[i][j]:
                continue
            num = cur_state[i][j]  # 获取当前结点在状态矩阵中的值
            # 如果当前结点的值为0(空白格),则将目标位置设置为状态矩阵的右下角
            if num == 0:
                x = N - 1
                y = N - 1
            # 如果当前结点的值不为0,则根据当前结点的值计算其目标位置,假设目标位置为(x,y)
            else:
                x = num / N
                y = num - N * x - 1
            # 计算当前结点与目标位置之间的曼哈顿距离,并累加到总距离中
            dist += (abs(x - i) + abs(y - j))
    # 返回计算得到的曼哈顿距离作为当前结点到目标结点的估计代价
return dist

生成子结点函数

def generate_child(cur_node, end_node, hash_set, open_table, dis_fn):
    # 如果当前结点就是目标结点,则直接将目标结点假如OPEN表,并返回,表示已经找到了解
    if cur_node == end_node:
        heapq.heappush(open_table, end_node)
        return
    # 获取当前结点状态矩阵的大小
    num = len(cur_node.state)
    # 遍历当前结点状态矩阵的每一个位置
    for i in range(0, num):
        for j in range(0, num):
            # 如果当前位置不是空格,则跳过,因为空格是可以移动的位置
            if cur_node.state[i][j] != 0:
                continue
            # 遍历当前位置的四个邻居位置,即上下左右四个方向
            for d in direction:
                x = i + d[0]
                y = j + d[1]
                if x < 0 or x >= num or y < 0 or y >=num:
                    continue
                # 记录生成的结点数量
                global SUM_NODE_NUM
                SUM_NODE_NUM += 1
                # 交换空格和邻居位置的数字,生成一个新的状态矩阵
                state = copy.deepcopy(cur_node.state)
                state[i][j], state[x][y] = state[x][y], state[i][j]
                # 计算新状态矩阵的哈希值,并检查是否已经在哈希集合中存在,如果存在则表示已经生成过相同的状态,跳过
                h = hash(str(state))
                if h in hash_set:
                    continue
                # 将新状态的哈希值添加到哈希集合中,计算新状态结点的gn(从起始结点到当前结点的代价)和hn(当前结点到目标结点的估计代价)
                hash_set.add(h)
                gn = cur_node.gn + 1
                hn = dis_fn(cur_node, end_node)
                # 创建新的状态结点对象,并将其加入到当前结点的子结点列表中,并将其加入到OPEN表中。
                node = State(gn, hn, state, h, cur_node)
                cur_node.child.append(node)
                heapq.heappush(open_table, node)

结果:
在这里插入图片描述

4、实验存在的问题与体会
学会了用A算法解决搜索问题,在搜索的时候比之前的盲目搜索用时更少,在其他搜索问题上用A算法也可以比盲目搜索更有效率,但前提是找到合适的估计函数。

2、编程实现一字棋游戏人机对弈,在九宫格棋盘上人机轮流在棋盘上摆各自的棋子,每次一枚,谁先取得三子一线结果的一方获胜。 (请用极小极大值搜索算法或α-β剪枝算法实现)
在这里插入图片描述

1、需求分析
用极小极大值搜索算法或α-β剪枝算法编程实现一字棋游戏人机对弈,在九宫格棋盘上人机轮流在棋盘上摆各自的棋子,每次一枚,谁先取得三子一线结果的一方获胜。
2、数据结构、功能模块设计与说明
关于核心判断部分 maxmin()解释:

该函数根据当前游戏状态的得分,计算出下一步应该走的位置。该函数的参数如下:

board:表示当前的游戏状态,是一个 3x3 的二维数组。
depth:表示搜索的深度,即预测未来多少步。
alpha:表示当前最好的评分(对于 maximizing 玩家来说),初始化为负无穷。
beta:表示当前最好的评分(对于 minimizing 玩家来说),初始化为正无穷。
maximizing:表示当前是轮到哪个玩家走棋,True 表示 maximizing 玩家,False 表示 minimizing 玩家。
该函数的返回值包括两个元素:

best_score:表示当前的最优得分。
best_move:表示当前应该走的位置。
在函数内部,首先使用 check_win 和 check_tie 函数判断当前游戏状态,如果存在胜负或平局,则返回对应的得分。如果还没有到达搜索的深度,则进入下一步的搜索。

如果当前是 maximizing 玩家,则使用 for 循环遍历棋盘中所有空位,对于每个空位,都假设 maximizing 玩家会走这个位置,并计算下一步的得分。如果得分比当前最优得分更好,则更新最优得分和最优位置。同时,更新 alpha 的值为当前最优得分和 alpha 中的最大值。如果 beta 的值小于或等于 alpha,则可以停止搜索并返回结果。

如果当前是 minimizing 玩家,则与 maximizing 玩家的情况类似,只是更新的是 beta 的值。
最终返回当前的最优得分和最优位置。

3、核心代码(不要将全部代码贴在报告上)与测试结果说明
核心代码:
minmax函数

# 极大极小/α-β剪枝算法
def minmax(board, depth, alpha, beta, maximizing):
    if check_win(board, "X"):
        return -10, None
    if check_win(board, "O"):
        return 10, None
    if check_tie(board):
        return 0, None
    if maximizing:
        best_score = -math.inf
        best_move = None
        for row in range(3):
            for col in range(3):
                if board[row][col] == " ":
                    board[row][col] = "O"
                    score, _ = minmax(board, depth - 1, alpha, beta, False)
                    board[row][col] = " "
                    if score > best_score:
                        best_score = score
                        best_move = (row, col)
                    alpha = max(alpha, best_score)
                    if beta <= alpha:
                        break
        return best_score, best_move
    else:
        best_score = math.inf
        best_move = None
        for row in range(3):
            for col in range(3):
                if board[row][col] == " ":
                    board[row][col] = "X"
                    score, _ = minmax(board, depth - 1, alpha, beta, True)
                    board[row][col] = " "
                    if score < best_score:
                        best_score = score
                        best_move = (row, col)
                    beta = min(beta, best_score)
                    if beta <= alpha:
                        break
        return best_score, best_move

结果:
在这里插入图片描述

4、实验存在的问题与体会
掌握了极大极小值搜索算法和α-β算法的算法思想。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VSTO(C#)Excel开发9:处理格式和字体

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

LinkedList底层结构和源码分析(JDK1.8)

参考视频&#xff1a;韩顺平Java集合 特点 LinkedList 底层实现了 双向链表 和 双端队列 的特点。可以添加任意元素&#xff08;元素可以重复&#xff09;&#xff0c;包括 null。线程不安全&#xff0c;没有实现同步。 LinkedList 底层结构 LinkedList 底层维护了一个双向链…

数字内容体验的技术支柱是什么?

数据分析引擎构建基础 数字内容体验的技术底座始于对海量用户行为数据的深度解析。作为技术体系的根基&#xff0c;数据分析引擎通过实时采集、清洗与结构化处理&#xff0c;将分散的点击轨迹、停留时长及交互偏好转化为可操作的洞察。其核心能力体现在三方面&#xff1a;一是…

C# 使用Markdown2Pdf把md文件转换为pdf文件

NuGet安装Markdown2Pdf库&#xff0c;可以把格式简单markdown文件转换为pdf。但该库用了Puppeteer Sharp&#xff0c;因此会在运行过程中提示指定Chrome浏览器路径或自动下载Chrome浏览器。 代码如下&#xff1a; using Markdown2Pdf;var converter new Markdown2PdfConverte…

专家系统如何运用谓词逻辑进行更复杂的推理

前文&#xff0c;我们讲解了命题逻辑和谓词逻辑的基本概念、推理规则、应用以及一些简单的示例。具体内容可以先看我的文章&#xff1a;人工智能的数学基础之命题逻辑与谓词逻辑&#xff08;含示例&#xff09;-CSDN博客 那么形如专家系统这类复杂系统&#xff0c;是如何通过谓…

html css网页制作成品——糖果屋网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…

落雪音乐Pro 8.8.6 | 内置8条音源,无需手动导入,纯净无广告

洛雪音乐Pro版内置多组稳定音源接口&#xff0c;省去手动导入的繁琐操作&#xff0c;安装即可畅听海量音乐。延续原版无广告的纯净体验&#xff0c;支持歌单推荐与音源切换&#xff0c;满足个性化听歌需求。此版本仅支持在线播放&#xff0c;无法下载音乐&#xff0c;且与原版不…

什么是全栈?

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点下班 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 &#x1f4c3;文章前言 &#x1f537;文章均为学习工…

XML文件格式的简介及如何用Python3处理XML格式对象

诸神缄默不语-个人技术博文与视频目录 文章目录 1. XML格式简介2. 格式化XML文件的工具3. Python处理XML&#xff1a;xml库1. xml.etree.\(c\)ElementTree2. xml.dom.minidom 4. 本文撰写过程中参考的其他网络资料 1. XML格式简介 可扩展标记语言 (Extensible Markup Language…

通过qemu仿真树莓派系统调试IoT固件和程序

通过qemu仿真树莓派系统调试IoT固件和程序 本文将介绍如何使用 QEMU 模拟器在 x86 架构的主机上运行 Raspberry Pi OS&#xff08;树莓派操作系统&#xff09;。我们将从下载镜像、提取内核和设备树文件&#xff0c;到启动模拟环境&#xff0c;并进行一些常见的操作&#xff0…

Oracle底层原理解析

Oracle 解析 1、union \ union all \ Intersect \ Minus内部处理机制&#xff08;优化&#xff09; 当查询语句中的where子句中使用到or时&#xff0c;可以用union all来代替。因为使用or查询语句的时候&#xff0c;引起全表扫描&#xff0c;并走索引查询 特别&#xff1a;当…

深度解读DeepSeek部署使用安全(48页PPT)(文末有下载方式)

深度解读DeepSeek&#xff1a;部署、使用与安全 详细资料请看本解读文章的最后内容。 引言 DeepSeek作为一款先进的人工智能模型&#xff0c;其部署、使用与安全性是用户最为关注的三大核心问题。本文将从本地化部署、使用方法与技巧、以及安全性三个方面&#xff0c;对Deep…

【前端三剑客】万字总结JavaScript

一、初识JavaScript 1.1 JavaScript 的作用 表单动态校验&#xff08;密码强度检测&#xff09; &#xff08; JS 产生最初的目的 &#xff09;网页特效服务端开发(Node.js)桌面程序(Electron)App(Cordova)控制硬件-物联网(Ruff)游戏开发(cocos2d-js) 1.2 HTML/CSS/JS 的关系…

【哈希表与字符串的算法之路:思路与实现】—— LeetCode

文章目录 两数之和面试题01.02.判定是否为字符重排存在重复元素存在重复元素||字母异位词分组最长公共前缀和最长回文子串二进制求和字符串相乘 两数之和 这题的思路很简单&#xff0c;在读完题目之后&#xff0c;便可以想到暴力枚举&#xff0c;直接遍历整个数组两遍即可&…

Hello Mr. My Yesterday日文歌词附假名注音,祭奠逝去的青春

hello mr. my yesterday Hundred Percent Free Hello Mr. my yesterday云っておくれよ “夢叶うその瞬間にまた逢える”と 前方の幾多前途多難の未知 後方の道後悔も知った 経験と価値 夢なかば 一本の道結果だが ひとつだけ知りたいよ 神様がいるのなら “幸せの定義っ…

ubuntu ollama+dify实践

安装ollama 官网的指令太慢了&#xff0c;使用以下指令加速&#xff1a; export OLLAMA_MIRROR"https://ghproxy.cn/https://github.com/ollama/ollama/releases/latest/download" curl -fsSL https://ollama.com/install.sh | sed "s|https://ollama.com/dow…

S7-1200 G2移植旧版本S7-1200程序的具体方法示例

S7-1200 G2移植旧版本S7-1200程序的具体方法示例 前期概要: S7-1200 G2必须基于TIA博途V20,之前的程序可通过移植的方式在新硬件上使用。 该移植工具可自动将TIA Portal 项目从 S7-1200 移植到更新的S7-1200 G2。 注意: 该插件支持在同一TIA Portal项目实例内将软件和/或硬…

新办公室哪款空气净化器除甲醛效果好?高效除甲醛,提升效率

现代办公环境中&#xff0c;空气质量对员工的健康与工作效率产生着不可忽视的影响。尤其是新装修的办公室&#xff0c;往往因为空气中的甲醛浓度超标而导致一系列健康问题。因此&#xff0c;选择一款性能优越的除甲醛空气净化器就显得尤为重要。合适的空气净化器不仅可以有效过…

大视频背景暗黑风格的wordpress企业主题免费下载

整体风格是黑色的&#xff0c;首页首屏大视频背景&#xff0c;动态效果非常好。向下滚动时&#xff0c;滚动的特效也不错。 原文 https://www.bixugao.com/wp/26.html

C语言基础知识04

指针 指针概念 指针保存地址&#xff0c;地址是字节的编号 指针类型和保存的地址类型要一直 使用时注意&#xff0c;把地址转换为&变量的格式来看 int a[3]; a转为&a[0] 指针的大小 64bit 固定8字节&#xff0c; 32bit 固定4字节 指针…