人工智能:一种现代的方法 第三章 经典搜索 中

news2024/11/28 20:41:50

文章目录

    • 前言
    • 人工智能:一种现代的方法 第三章 经典搜索 中
    • 3.4 无信息搜索
      • 3.4.1 宽度优先搜索
      • 3.4.2 一致代价搜索
      • 3.4.3 深度优先搜索
      • 3.4.4 DFS BFS UCS 之间的对比
      • 3.4.5 深度受限搜索 与迭代加深
      • 3.4.6双向搜索
      • 3.4.7无信息搜索策略对比
    • 总结

前言

我觉得具体搜索策略的在该书有两点不足,一是伪代码难以理解,二是没有具体例子帮助理解。所以本文用python伪代码代替,以及收集一些例子供大家参考

人工智能:一种现代的方法 第三章 经典搜索 中

3.4 无信息搜索

3.4.1 宽度优先搜索

def BFS(graph, start, goal):
    queue = []  # 初始化一个队列
    visited = set()  # 初始化一个已访问节点的集合

    queue.append([start])  # 将起始节点的路径加入队列

    while queue:  # 当队列不为空时
        path = queue.pop(0)  # 从队列中取出一个路径
        node = path[-1]  # 获取路径中的最后一个节点

        if node not in visited:  # 如果该节点没有被访问过
            if node == goal:  # 如果该节点是目标节点
                return path  # 返回该路径

            visited.add(node)  # 将该节点加入已访问节点的集合

            for neighbor in graph[node]:  # 遍历当前节点的所有邻居节点
                new_path = list(path)  # 创建一个新路径
                new_path.append(neighbor)  # 将邻居节点加入新路径
                queue.append(new_path)  # 将新路径加入队列

    return "无解"  # 如果没有从起始节点到目标节点的路径,则返回"无解"

性能分析

  • 完备性:若b有限,则算法完备
  • 最优性:当动作耗散值相同时,算法最优
  • 时间复杂度
    在结点被扩展生成时进行目标测试,结点数为b+b2+b3+…+bd=O(b^d)
    在结点被选择扩展时进行目标测试,结点数为O(b^(d+1))
  • 空间复杂度
    探索集O(b^(d-1)) 个结点,边缘集O(b^d)个结点

迷宫问题
一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

注:利用bfs特殊最优性

void bfs () {
    queue <PII> q;
    q.push ({n,n});
    memset (pre,-1,sizeof (pre));
    pre[n][n] = {1,1};
    while (!q.empty ()) {
        PII t = q.front ();
        q.pop ();
        for (int i = 0;i < 4;i++) {
            int a = t.x + dx[i],b = t.y + dy[i];
            if (a < 1 || a > n || b < 1 || b > n) continue;
            if (g[a][b]) continue;
            if (pre[a][b].x != -1) continue;
            q.push ({a,b});
            pre[a][b] = t;
        }
    }
}

3.4.2 一致代价搜索

import heapq  # 用于实现优先队列

def UCS(graph, start, goal):
    queue = []  # 初始化优先队列
    visited = set()  # 初始化已访问节点集合

    # 将起始节点的路径以及到达该节点的总成本加入队列
    # (路径成本,路径)作为元组存入队列,路径成本作为优先级
    heapq.heappush(queue, (0, [start]))

    while queue:  # 当队列不为空时
        (cost, path) = heapq.heappop(queue)  # 取出当前成本最小的路径
        node = path[-1]  # 获取路径中的最后一个节点

        if node not in visited:  # 如果该节点没有被访问过
            if node == goal:  # 如果该节点是目标节点
                return path  # 返回该路径

            visited.add(node)  # 将该节点加入已访问节点的集合

            for neighbor in graph[node]:  # 遍历当前节点的所有邻居节点
                new_cost = cost + graph[node][neighbor]  # 计算新路径的总成本
                new_path = list(path)  # 创建一个新路径
                new_path.append(neighbor)  # 将邻居节点加入新路径
                heapq.heappush(queue, (new_cost, new_path))  # 将新路径加入队列

    return "无解"  # 如果没有从起始节点到目标节点的路径,则返回"无解"

性能分析

  • 若存在耗散值为0的动作NOOP,则可能陷入死循环,算法不完备
    若b有限且动作的耗散值均不为0,则算法完备
  • 最优性:最优,C*表示最优解路径的耗散值
  • 时间复杂度:一致代价搜索>宽度优先搜索

当动作耗散值相同时,除了目标测试的时间点不同之外,一致代价搜索退化为宽度优先搜索
请添加图片描述

单源最短路问题
有一个 n 个点 m 条边的无向图,请求出从 s 到 t 的最短路长度。

注:利用最优性求解


int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});

    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second, distance = t.first;

        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

3.4.3 深度优先搜索

def DFS(graph, start, goal):
    stack = []  # 初始化一个栈
    visited = set()  # 初始化一个已访问节点的集合

    stack.append([start])  # 将起始节点的路径加入栈

    while stack:  # 当栈不为空时
        path = stack.pop()  # 从栈中取出一个路径
        node = path[-1]  # 获取路径中的最后一个节点

        if node not in visited:  # 如果该节点没有被访问过
            if node == goal:  # 如果该节点是目标节点
                return path  # 返回该路径

            visited.add(node)  # 将该节点加入已访问节点的集合

            for neighbor in graph[node]:  # 遍历当前节点的所有邻居节点
                new_path = list(path)  # 创建一个新路径
                new_path.append(neighbor)  # 将邻居节点加入新路径
                stack.append(new_path)  # 将新路径加入栈

    return "无解"  # 如果找不到路径,返回“无解”

性能分析

  • 时间复杂度最多生成O(b^m)个结点,可能大于状态空间的规模,m可能是无限的
  • 空间复杂度(优势)
    当一个结点的所有子结点均被探索,则该结点可以删除仅需存储一条从根结点到叶结点的路径,以及该路径上每个结点的所有未被扩展的兄弟结点,O(bm)

深度优先搜索的变体——回溯搜索(一般dfs都由递归实现)

n皇后问题
请添加图片描述

void dfs(int u)
{
    if (u == n)
    {
        for (int i = 0; i < n; i ++ ) puts(g[i]);
        puts("");
        return;
    }

    for (int i = 0; i < n; i ++ )
        if (!col[i] && !dg[u + i] && !udg[n - u + i])
        {
            g[u][i] = 'Q';
            col[i] = dg[u + i] = udg[n - u + i] = true;
            dfs(u + 1);
            col[i] = dg[u + i] = udg[n - u + i] = false;
            g[u][i] = '.';
        }
}

3.4.4 DFS BFS UCS 之间的对比

搜索算法搜索方式最优性
深度优先搜索 (DFS)利用栈的后进先出特性,从根节点开始,尽可能深地搜索图的分支,直到当前分支没有更多的节点可以访问,然后回溯到上一个节点,继续搜索下一个分支。不保证找到最短路径。
广度优先搜索 (BFS)利用队列的先进先出特性,从根节点开始,先访问所有的邻居节点,然后再访问邻居的邻居。总是优先搜索离根节点最近的节点,因此它可以找到最短路径(假设所有的边的权重都相同)。
一致性搜索 (UCS)使用优先队列来存储待访问的节点,节点的优先级根据从根节点到该节点的路径的总权重(成本)来确定。总是优先搜索路径成本最小的节点,因此它可以找到最短路径,即使边的权重不相同。

3.4.5 深度受限搜索 与迭代加深

迭代加深与深度受限搜索往往结合在一使用,所以本文便放在一起讲解

深度受限搜索

  • 添加了深度界限limit(简记为l):深度为l的结点当做叶结点对待
  • 完备性:当l<d时,算法不完备
  • 最优性:当l>d时,算法非最优
  • 时间复杂度:O(b^l)
  • 空间复杂度:O(bl)

当l=∞时,深度受限搜索退化为深度优先搜索

迭代加深的深度优先搜索

  • 完备性:若b有限,则算法完备
  • 最优性:
    若路径耗散是结点深度的非递减函数,则算法最优
    当动作耗散值相同时,算法最优
  • 时间复杂度:db+(d-1)b2+(d-2)b3+…+1bd=O(b^d)
  • 空间复杂度:O(b^d)
def IDS(graph, start, goal):
    depth = 0  # 初始化深度限制

    while True:  # 持续搜索,直到找到目标
        result = DLS(graph, start, goal, depth)  # 进行深度有限搜索
        if result != "无解":  # 如果找到了解
            return result  # 返回结果
        depth += 1  # 增加深度限制


def DLS(graph, node, goal, depth):
    if depth == 0 and node == goal:  # 如果达到深度限制且找到目标
        return [node]  # 返回包含当前节点的路径
    elif depth > 0:  # 如果还没有达到深度限制
        for neighbor in graph[node]:  # 遍历当前节点的所有邻居节点
            result = DLS(graph, neighbor, goal, depth - 1)  # 对邻居节点进行深度有限搜索
            if result != "无解":  # 如果找到了解
                return [node] + result  # 返回包含当前节点和找到的路径的路径

    return "无解"  # 如果没有找到解,返回"无解"

埃及分数问题
把一个分数分为几个不同的分子为 1 的最简分数,要求分成的分数的分母中不能出现

int ok = 0;
for (maxd = 1;; maxd++) {
    memset(ans, -1, sizeof(ans));
    if (dfs(0, get_first(a, b), a, b)) {
        ok = 1;
        break;
    }
}

// 如果当前解v比目前最优解ans更优,更新ans
bool better(int d) {
    for (int i = d; i >= 0; i--) {
        if (v[i] != ans[i]) {
            return ans[i] == -1 || v[i] < ans[i];
        }
    }
    return false;
}

// 当前深度为d,分母不能小于from,分数之和恰好为aa/bb
bool dfs(int d, int from, LL aa, LL bb) {
    if (d == maxd) {
        if (bb % aa) return false;  // aa/bb必须是埃及分数
        v[d] = bb / aa;
        if (better(d)) memcpy(ans, v, sizeof(LL) * (d + 1));
        return true;
    }

    bool ok = false;
    from = max(from, get_first(aa, bb));  // 枚举的起点
    for (int i = from;; i++) {
        // 剪枝:如果剩下的maxd+1-d个分数全部都是1/i,加起来仍然不超过aa/bb,则无解
        if (bb * (maxd + 1 - d) <= i * aa) break;
        v[d] = i;
        // 计算aa/bb - 1/i,设结果为a2/b2
        LL b2 = bb * i;
        LL a2 = aa * i - bb;
        LL g = gcd(a2, b2);  // 以便约分
        if (dfs(d + 1, i + 1, a2 / g, b2 / g)) ok = true;
    }
    return ok;
}

3.4.6双向搜索

  • 两个搜索同时运行:一个从初始状态向前搜索,另一个从目标状态向后搜索,直到状态相遇
  • 目标测试:检查两个搜索的边缘集是否相交

性能分析

  • 最优性:非最优
  • 双向宽度优先搜索的时间复杂度:O(b^(d/2))
  • 双向宽度优先搜索的空间复杂度:O(b^(d/2))
  • 难点:需要计算父节点的算法和明确的目标状态

3.4.7无信息搜索策略对比

在这里插入图片描述

总结

本文讲了具体搜索中无信息算法,并对比了无信息搜索策略性能对比。希望各位能仔细思考之间的关系与差别并深思我收集的例题。
下篇文章将介绍有信息搜索算法,以及启发式函数。不要走开,马上回来,各位敬请期待。

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

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

相关文章

全国手机基站数据!总量近1640000条数据!

上周大家的投票都收到啦&#xff01;由于多个数据打成了平局&#xff0c;这周就准备给大家先分享一波卫星运用数据&#xff01; 今天分享的是全国手机基站数据&#xff0c;微信订阅号“citybox城市沙盒”回复“手机基站”即可获取数据 随着移动通信技术的不断发展&#xff0c;…

阿里云百炼将于2023年10月30日起面向新老用户赠送限时免费流量包。有兴趣的可以领取下来玩一玩

在云栖大会现场&#xff0c;周靖人发布一站式大模型应用开发平台——阿里云百炼&#xff0c;该平台集成了国内外主流优质大模型&#xff0c;提供模型选型、微调训练、安全套件、模型部署等服务和全链路的应用开发工具&#xff0c;为用户简化了底层算力部署、模型预训练、工具开…

自动化测试:在Linux下搭建接口自动化测试平台详解

我们今天来学习一下在Linux下如何搭建基于HttpRunner开发的接口自动化测试平台吧&#xff01; 需要在Linux上提前准备的环境&#xff08;下面是本人搭建时的环境&#xff09;&#xff1a; 1&#xff0c;Python 3.6.8 2&#xff0c;MySQL 5.7 在这我也准备了一份软件测试视…

初始Pandas -> 数据缺失值处理

&#x1f43c; 3.1初识pandas&#xff08;显示excel前五条数据&#xff09; 3.2创建Series对象 3.2.1手动设置索引 3.2.4Series的索引 3.3创建一个DataFrame对象 3.4导入外部数据 p59 1.使用read_csv 2.导入html时,需要网页一定具有table标签 3.5数据抽取 3.6数据的增加、修…

了解web3,什么是web3

Web3是指下一代互联网&#xff0c;它基于区块链技术&#xff0c;将各种在线活动更加安全、透明和去中心化。Web3是一个广义的概念&#xff0c;它包括了很多方面&#xff0c;如数字货币、去中心化应用、智能合约等等。听不懂且大多数人听到这个东西&#xff0c;直觉感觉就像骗子…

3dmax经常渲染失败?优化方法提升渲染质量!

3DMAX是一款专业的三维建模、动画和渲染软件&#xff0c;被广泛应用于影视、游戏、建筑、广告等领域。 而云渲染是一种利用云计算技术&#xff0c;将渲染任务分配到海量的服务器上进行并行计算的服务&#xff0c;能够显著提升渲染效率和质量&#xff0c;节省时间和成本。 使用…

数据分析案例-基于服饰行业中消费者行为和购物习惯的可视化分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

HTML5+CSS3实现华为鸿蒙官网(课程设计完整版)

前言 这是一个用HTML5CSS3实现的一个华为鸿蒙官网。 文章结构相对简单&#xff0c;容易理解。适合学生当课程大作业使用&#xff01; 同时如果因要满足作业要求而需要修改内容的也可以联系我&#xff01; 下面是一些其他页面的作品&#xff0c;同样希望能给大家带来帮助&#…

Android Studio(列表视图ListView)

前言 前面在适配器章节&#xff0c;已经介绍了ListView的作用(干什么的)&#xff0c;这节将主要介绍如何去设计ListView页面视图。 思考 列表视图需要些什么&#xff1f; 1. 列表项容器&#xff08;装载各列表项的容器&#xff09;&#xff1a;<ListView/> 2. 列表项布局…

淘宝平台API接口的接入参数及说明(附获取获得淘宝商品详情获得淘宝商品详情高级版获得淘宝商品评论获得淘宝商品快递费用获取获取买卖家的订单详情)

前言 在古代&#xff0c;我们的传输信息的方式有很多&#xff0c;比如写信、飞鸽传书&#xff0c;以及在战争中使用的烽烟&#xff0c;才有了著名的烽火戏诸侯&#xff0c;但这些方式传输信息的效率终究还是无法满足高速发展的社会需要。如今万物互联的时代&#xff0c;我通过…

UE5——源码阅读——7——引擎预初始化

创建一个性能计数器&#xff0c;用于统计引擎在初始化性能 加载核心模块 是否记录配置文件信息 是否记录Pak文件信息 记录配置文件和Pak文件 初始化渲染相关的变量 没有编辑器标记和命令行标记 拿到当前日志的指针 初始化Oodle(是4.27引入的压缩算法) 读取模块 加载…

如何释放React Hooks的力量

React是用于构建用户界面的一个流行JavaScript库&#xff0c;多年来已经发生了重大变化和改进。React中最具颠覆性的新特性之一就是引入了Hooks。React Hooks彻底改变了开发者在函数组件中管理状态和生命周期的方式。在这个全面的指南中&#xff0c;将深入研究React Hooks的世界…

小菜React

1、Unterminated regular expression literal, 对于函数就写.ts&#xff0c;有dom元素就写.tsx 2、 The requested module /src/components/setup.tsx?t1699255799463 does not provide an export named Father export default useStore默认导出的钩子&#xff0c;组件引入的…

2023年北京市安全员-C3证证模拟考试题库及北京市安全员-C3证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年北京市安全员-C3证证模拟考试题库及北京市安全员-C3证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;北京市安全员-C3证证模拟考试题库是根据北京市安全员-C3证最新版教材&#xff0c;北京市安全员-C…

入参mm²出现乱码情况

原因是因为编码时使用的是JS的unescape()函数 换成 JS的decodeURI&#xff08;&#xff09;函数即可

YoungGC 停顿超长时间调优

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

Python语言高级实战-内置函数super()的使用之类的单继承(附源码和实现效果)

实现功能 super()是一个内置函数&#xff0c;用于调用父类的方法。super() 是用来解决多重继承问题的&#xff0c;直接用类名调用父类方法在使用单继承的时候没问题&#xff0c;但是如果使用多继承&#xff0c;会涉及到查找顺序&#xff08;MRO&#xff09;、重复调用&#xf…

微服务架构——笔记(3)Eureka

微服务架构——笔记&#xff08;3&#xff09; 基于分布式的微服务架构 本次笔记为 此次项目的记录&#xff0c;便于整理思路&#xff0c;仅供参考&#xff0c;笔者也将会让程序更加完善 内容包括&#xff1a;1.支付模块、2.消费者订单模块、支付微服务入驻Eureka、Eureka集群…

解决SpringBoot项目端口被占用的问题

问题描述&#xff1a; 在Window环境下&#xff0c;运行SpringBoot 项目时&#xff0c;出现端口被占用的问题&#xff1a; 解决方案&#xff1a; 1. 查看对应端口的进程号 netstat -ano | findstr 80802. 查看对应进程号的信息 tasklist | findstr 477963. 根据进程号 kill 进程…

01-Spring中事务的实现之编程式事务和声明式事务,以及事务的属性之传播行为,隔离级别,事务的回滚

银行账户转账异常 需求: 实现act-001账户向act-002账户转账10000,要求两个账户的余额一个减成功一个加成功,即执行的两条update语句必须同时成功或失败 实现步骤 第一步: 引入项目所需要的依赖 <?xml version"1.0" encoding"UTF-8"?> <proj…