AI A_star算法野人渡河-实验报告

简介: AI A_star算法野人渡河-实验报告

1、 问题描述及实验要求


      请用A*算法实现野人过河问题,(1)分析设计估价函数f(2)采用C语言或Python编程实现(代码中适当加注释,输出具有可读性)。

      问题描述:设有m个传教士和n个野人来到河边,打算乘一只船从左岸渡到右岸去,该船每次最多载3人。在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。他们怎样才能用这条船安全地把所有人都渡河过去?试采用宽带优先和深度优先方法分析搜索过程。(说明:传教士和野人都会划船,测试:m=n=3)

2、 算法描述


  1. 构造状态空间
    这个题目的状态空间秒数为一组整数对(a,b,flag)。
  2. a是左边岸上剩下的传教士数

b是左边岸上剩下的野人数目

flag取值为1时,船在左岸;flag取值为0是,船在右岸。

所以,初始状态为(m,n,1),目的状态为(0,0,0)。

  1. 设计节点的数据结构
          可以想象到,这个题目应该采用树形结构来解,所以如何建立每个节点的数据结构就是难点。这里我是用Python写的算法,结点的数据结构如下:
class Point:
    def __init__(self, a, b, flag):
        self.a = a  # 左岸传教士数量
        self.b = b  # 左岸野人数量
        self.flag = flag  # flag = 1: 船在左岸;flag = 0: 船在右岸
        self.father = None
        self.node = [a, b, flag]
        self.g = 0
        self.f = 0  # f = g+h

  比较重要的是Point结点的father属性,指明了子节点与父节点的关系,保证了树形结构的准确性。g属性代表节点的深度,f是启发信息。

  1. 代码运行介绍

i 首先定义了传教士数目、野人数目、open表、closed表,声明了Point类,定义了初始节点init(3,3,3)和目的节点(0,0,0)。

ii 在开始进行A_star算法之前,先定义几个函数:

1) safe:判断该节点内在左岸、右岸、船舶上的传教士数目是否大于野人数目或者有一方为0;

2) equal:判断两个节点是否相同。这里防止组合“爆炸”(老师上课说的)或者说是死循环。这里是为了检测OPEN表和CLOSED表写的函数;

3) back:判断该节点是否是父节点,防止节点重复;

4) in_list:判断这个节点是否在某个表中。用来判断新生成的节点是否在OPEN表或者CLOSED表中。

5) h:启发信息。返回的是该节点时,左岸剩下的野人数与传教士数减去船的容量乘以flag,即:s.a + s.b –K * s.flag。因为作为启发信息,从起点到目标节点时,此时用的h启发信息是经过推导的最小步骤数,相当于h*。

6) open_sort:根据节点的f属性的大小,对OPEN表里面的节点排序

iii 开始编写BFS算法和DFS算法:

1) 首先,先把初始节点init放入到OPEN表中,然后遍历OPEN表;

2) 如果OPEN中取出的节点是目的节点goal,那么结束遍历;否则把这个节点从OPEN表取出,放入CLOUSED表;

3) 然后根据此节点,来得到它的子节点,它的子节点要满足几个规则:符合题目规定的安全问题;不是父节点;不在OPEN表中;不在CLOUSED表中;

4) 把该节点的f属性、father属性、g属性指定好。判断该new节点是否已经出现在open表中,如果已经出现了而且它的f属性值更好,说明它更优,那么把之前的移除,把这个插入。Open表同理。如果该new节点在open表和closed表都没有,那么把它直接插入到open表。最后根据f属性的值,对open表的节点排序。

iV 最后打印一下路径,就可显示出解。

3、 代码


import operator
A = 3  # 传教士数量
B = 3  # 野人数量
K = 3  # 最大乘坐人数量
OPEN = []  # open表
CLOSED = []  # closed表
class Point:
    def __init__(self, a, b, flag):
        self.a = a  # 左岸传教士数量
        self.b = b  # 左岸野人数量
        self.flag = flag  # flag = 1: 船在左岸;flag = 0: 船在右岸
        self.father = None
        self.node = [a, b, flag]
        self.g = 0
        self.f = 0  # f = g+h
init = Point(A, B, 1)  # 初始节点
goal = Point(0, 0, 0)  # 目标节点
# 启发函数
def h(s):
    return s.a + s.b - K * s.flag
# 判断传教士是否安全
def safe(s):
    if s.a > A or s.a < 0 or s.b > B or s.b < 0 or (s.a != 0 and s.a < s.b) or (s.a != A and A - s.a < B - s.b):
        return False
    else:
        return True
def equal(a, b):
    if a.node == b.node:
        return True
# 判断当前状态与父状态是否一致
def back(new, s):
    if s.father is None:
        return False
    return equal(new, s.father)
# 将open_list以f值进行排序
def open_sort(l):
    the_key = operator.attrgetter('f')  # 指定属性排序的key
    l.sort(key=the_key)
# 扩展节点时在open表和closed表中找原来是否存在相同mcb属性的节点
def in_list(new, l):
    for item in l:
        if new.node == item.node:
            return True, item
    return False, None
def A_star(s):
    global OPEN, CLOSED
    OPEN = [s]
    CLOSED = []
    while OPEN:  # open表非空
        get = OPEN[0]  # 取出open表第一个元素get
        if get.node == goal.node:  # 判断是否为目标节点
            return get
        OPEN.remove(get)  # 将get从open表移出
        CLOSED.append(get)  # 将get加入closed表
        # 以下得到一个get的新子节点new并考虑是否放入open
        for i in range(A):  # 上船传教士
            for j in range(B):  # 上船野人
                # 船上非法情况
                if i + j == 0 or i + j > K or (i != 0 and i < j):
                    continue
                if get.flag == 1:  # 当前船在左岸,下一状态统计船在右岸的情况
                    new = Point(get.a - i, get.b - j, 0)
                else:  # 当前船在右岸,下一状态统计船在左岸的情况
                    new = Point(get.a + i, get.b + j, 1)
                if not safe(new) or back(new, get):  # 状态非法或new折返了
                    pass
                # 如果要拓展的节点满足以上情况,将它的父亲设为当前节点,计算f,并对open_list排序
                else:
                    new.father = get
                    new.g = get.g + 1  # 与起点的距离
                    new.f = get.g + h(get)  # f = g + h
                    # 如果new在open表中
                    if in_list(new, OPEN)[0]:
                        old = in_list(new, OPEN)[1]
                        if new.f < old.f:  # new的f<open表相同状态的f
                            OPEN.remove(old)
                            OPEN.append(new)
                            open_sort(OPEN)
                        else:
                            pass
                    # 继续,如果new在closed表中
                    elif in_list(new, CLOSED)[0]:
                        old = in_list(new, CLOSED)[1]
                        if new.f < old.f:
                            # 将old从closed删除,并重新加入open
                            CLOSED.remove(old)
                            OPEN.append(new)
                            open_sort(OPEN)
                        else:
                            pass
                    else:
                        OPEN.append(new)
                        open_sort(OPEN)
        print('OPEN表:')
        for o in OPEN:
            print(o.node,o.g,o.f)
# 递归打印路径
def printPath(f):
    if f is None:
        return
    printPath(f.father)
    print(f.node)
if __name__ == '__main__':
    final = A_star(init)
    if final:
        print('有解,解为:')
        printPath(final)
    else:
        print('无解!')

4、 实验结果分析


实验结果截图:

image.png

图1-A算法解决野人渡河

image.png

图2-A算法结果分析

5、 实验体会


A*算法有助于提高算法的效率,但是如何构建启发函数是关键。

在我看来,只要启发函数的值与初始状态到最终状态的趋势一致,那么这个启发函数就是可行的。比如,传教士与野人这题,趋势就是,传教士与野人的人数都是趋于减少,所以我设置启发函数为,两者的和,是可行的。

但是还要考虑到启发函数的值要尽量小的问题。

然而,最有效的启发函数,还是需要推导出公式来的。随便找的可能也行,但是效果可能不会好,效率也不会高。本题的启发函数是m+n-2,这是按照最小的步数,推导出来的结果。

相关文章
|
2月前
|
JSON 分布式计算 数据处理
加速数据处理与AI开发的利器:阿里云MaxFrame实验评测
随着数据量的爆炸式增长,传统数据分析方法逐渐显现出局限性。Python作为数据科学领域的主流语言,因其简洁易用和丰富的库支持备受青睐。阿里云推出的MaxFrame是一个专为Python开发者设计的分布式计算框架,旨在充分利用MaxCompute的强大能力,提供高效、灵活且易于使用的工具,应对大规模数据处理需求。MaxFrame不仅继承了Pandas等流行数据处理库的友好接口,还通过集成先进的分布式计算技术,显著提升了数据处理的速度和效率。
|
9天前
|
机器学习/深度学习 存储 人工智能
预定下一个诺奖级AI?谷歌量子纠错AlphaQubit登Nature,10万次模拟实验创新里程碑
谷歌的量子纠错算法AlphaQubit近日登上《自然》杂志,被誉为量子计算纠错领域的重大突破。量子比特易受环境噪声干扰,导致计算错误,而AlphaQubit通过神经网络学习噪声模式,显著提升纠错准确性。实验结果显示,它在Sycamore处理器和Pauli+模拟器上表现优异,优于现有解码算法。尽管面临资源需求高等挑战,AlphaQubit为实用化量子计算带来新希望,并可能推动其他领域创新。论文详见:https://www.nature.com/articles/s41586-024-08148-8
31 5
|
26天前
|
机器学习/深度学习 人工智能 算法
Transformer打破三十年数学猜想!Meta研究者用AI给出反例,算法杀手攻克数学难题
《PatternBoost: Constructions in Mathematics with a Little Help from AI》提出了一种结合传统搜索算法和Transformer神经网络的PatternBoost算法,通过局部搜索和全局优化交替进行,成功应用于组合数学问题。该算法在图论中的Ramsey数研究中找到了更小的反例,推翻了一个30年的猜想,展示了AI在数学研究中的巨大潜力,但也面临可解释性和通用性的挑战。论文地址:https://arxiv.org/abs/2411.00566
77 13
|
2月前
|
机器学习/深度学习 人工智能 算法
Enhance-A-Video:上海 AI Lab 推出视频生成质量增强算法,显著提升 AI 视频生成的真实度和细节表现
Enhance-A-Video 是由上海人工智能实验室、新加坡国立大学和德克萨斯大学奥斯汀分校联合推出的视频生成质量增强算法,能够显著提升视频的对比度、清晰度和细节真实性。
114 8
Enhance-A-Video:上海 AI Lab 推出视频生成质量增强算法,显著提升 AI 视频生成的真实度和细节表现
|
1月前
|
人工智能 运维 Serverless
低成本 Serverless AI 检索介绍和实验
本文介绍了低成本Serverless AI检索技术,分为四部分:1) AI检索介绍,通过电商客服案例展示AI检索的应用和优势;2) 表格存储介绍,详细解释了表格存储的结构化数据处理能力及其在AI检索中的作用;3) 实验:RAG,通过具体实验演示基于表格存储的RAG流程及效果;4) 总结,强调向量检索、易用性和丰富的接口特性。整体内容展示了如何利用Serverless架构实现高效、低成本的AI检索解决方案。
|
1月前
|
机器学习/深度学习 存储 人工智能
淘天算法工程师玩转《黑神话》,多模态大模型如何成为天命AI
淘天集团未来生活实验室的算法工程师们以ARPG游戏《黑神话:悟空》为平台,探索多模态大模型(VLM)在仅需纯视觉输入和复杂动作输出场景中的能力边界。他们提出了一种名为VARP的新框架,该框架由动作规划系统和人类引导的轨迹系统组成,成功在90%的简单和中等难度战斗场景中取得胜利。研究展示了VLMs在传统上由强化学习主导的任务中的潜力,并提供了宝贵的人类操作数据集,为未来研究奠定了基础。
|
2月前
|
机器学习/深度学习 缓存 人工智能
【AI系统】QNNPack 算法
QNNPACK是Marat Dukhan开发的量化神经网络计算加速库,专为移动端优化,性能卓越。本文介绍QNNPACK的实现,包括间接卷积算法、内存重排和间接缓冲区等关键技术,有效解决了传统Im2Col+GEMM方法存在的空间消耗大、缓存效率低等问题,显著提升了量化神经网络的计算效率。
56 6
【AI系统】QNNPack 算法
|
2月前
|
存储 人工智能 缓存
【AI系统】Im2Col 算法
Caffe 作为早期的 AI 框架,采用 Im2Col 方法优化卷积计算。Im2Col 将卷积操作转换为矩阵乘法,通过将输入数据重排为连续内存中的矩阵,减少内存访问次数,提高计算效率。该方法首先将输入图像转换为矩阵,然后利用 GEMM 库加速计算,最后将结果转换回原格式。这种方式显著提升了卷积计算的速度,尤其适用于通道数较多的卷积层。
72 5
【AI系统】Im2Col 算法
|
2月前
|
存储 机器学习/深度学习 人工智能
【AI系统】Winograd 算法
本文详细介绍Winograd优化算法,该算法通过增加加法操作来减少乘法操作,从而加速卷积计算。文章首先回顾Im2Col技术和空间组合优化,然后深入讲解Winograd算法原理及其在一维和二维卷积中的应用,最后讨论算法的局限性和实现步骤。Winograd算法在特定卷积参数下表现优异,但其应用范围受限。
58 2
【AI系统】Winograd 算法
|
2月前
|
人工智能 算法
AI+脱口秀,笑点能靠算法创造吗
脱口秀是一种通过幽默诙谐的语言、夸张的表情与动作引发观众笑声的表演艺术。每位演员独具风格,内容涵盖个人情感、家庭琐事及社会热点。尽管我尝试用AI生成脱口秀段子,但AI缺乏真实的情感共鸣和即兴创作能力,生成的内容显得不够自然生动,难以触及人心深处的笑点。例如,AI生成的段子虽然流畅,却少了那份不期而遇的惊喜和激情,无法真正打动观众。 简介:脱口秀是通过幽默语言和夸张表演引发笑声的艺术形式,AI生成的段子虽流畅但缺乏情感共鸣和即兴创作力,难以达到真人表演的效果。

热门文章

最新文章