A*——AcWing 178. 第K短路

A*

定义

A算法是一种广泛应用于路径搜索和图遍历的启发式搜索算法,它结合了最好优先搜索和Dijkstra算法的优点,旨在找到从初始节点到目标节点的最短路径。A算法在游戏AI、机器人导航、地图路线规划等领域有广泛应用。

A*算法的核心在于使用一个评估函数f(n)来确定下一个要探索的节点,该函数由两部分组成:

  1. 从起始节点到当前节点的实际代价 g(n)
  2. 从当前节点到目标节点的预估代价 h(n),这是通过启发式函数得到的,用于估计未来成本。

因此,对于每个节点n,A*算法计算的评估值为:f(n) = g(n) + h(n)

运用情况

  • 实时导航系统:如汽车导航、无人机路径规划,因为它能快速找到最优路径。
  • 游戏AI:例如角色的自动寻路,能够使NPC智能地选择通往目标的最短或最佳路径。
  • 机器人路径规划:帮助机器人在复杂环境中找到到达指定位置的最佳路径。
  • 图形用户界面中的自动布局:如自动布线算法中寻找最优布线方案。

注意事项

  1. 启发式函数的选择h(n)应该是一个乐观估计,即它不能过高估计实际成本,理想情况下应接近真实成本。常用的启发式函数有欧几里得距离、曼哈顿距离等。
  2. 空间与时间复杂度:A算法可能需要大量内存来存储已访问节点和待访问节点(优先队列),且在最坏情况下时间复杂度会较高。因此,优化数据结构(如使用A变种如IDA*或实现迭代深化)是必要的。
  3. 循环检测:在有向无环图中不会出现问题,但在更复杂的图中,需要额外机制避免无限循环。
  4. 终点可达性:确保目标节点是可达到的,否则算法将永远运行下去。

解题思路

  1. 初始化:设置起始节点的g(n)=0,其他所有节点的g(n)=∞,并将起始节点放入开放列表(优先队列,根据f(n)排序)。
  2. 循环:直到开放列表为空或找到目标节点。
    • 从开放列表中取出具有最小f(n)值的节点,称为当前节点。
    • 检查当前节点是否为目标节点,若是则结束,路径已找到。
    • 将当前节点移出开放列表并加入关闭列表,表示已访问过。
    • 遍历当前节点的所有邻居,对于每个未访问过的邻居:
      • 计算从起始点到该邻居的代价g(neighbor)
      • 计算启发式函数h(neighbor)
      • 更新邻居节点的总代价f(neighbor),如果新代价更低,则更新其父节点,并将其加入开放列表(如果不在其中)。
  3. 结束:若开放列表为空但未找到目标,说明没有路径;否则,通过回溯从目标到起始节点的父节点链,构建出最优路径。

AcWing 178. 第K短路

题目描述

AcWing 178. 第K短路 - AcWing

运行代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 1010, M = 200010;

int n, m, S, T, K;
int h[N], rh[N], e[M], w[M], ne[M], idx;
int dist[N], cnt[N];
bool st[N];

void add(int h[], int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra()
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    memset(dist, 0x3f, sizeof dist);
    heap.push({0, T});
    dist[T] = 0;
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.y;
        if(st[ver]) continue;
        st[ver] = true;
        for(int i = rh[ver]; ~i; 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});
            }
        }
    }
}
int astar()
{
    priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
    heap.push({dist[S], {0, S}});
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.y.y, distance = t.y.x;
        cnt[ver] ++ ;
        if(cnt[T] == K) return distance;
        for(int i = h[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if(cnt[j] < K) heap.push({dist[j] + distance + w[i], {distance + w[i], j}});
        }
    }
    return -1;
}
int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    memset(rh, -1, sizeof rh);
    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(h, a, b, c);
        add(rh, b, a, c);
    }
    cin >> S >> T >> K;
    if (S == T) K ++ ;
    dijkstra();
    cout << astar() << endl;

    return 0;
}

代码思路

  1. 数据结构定义:首先定义了用于表示边和节点对的pair类型,以及用于优先队列元素的三元组类型。同时定义了图的邻接表表示和相关变量。

  2. 图的构建:通过add函数向邻接表中添加边,这里维护了两个方向的边,一个在h[]中用于正向搜索(Dijkstra),另一个在rh[]中用于反向验证路径。

  3. Dijkstra算法:用于计算从目标点T到所有其他点的最短距离。这一步是预处理,为A*算法提供每一点到T的预估成本。

  4. A*搜索astar()函数实现了类似A*的搜索逻辑,尽管这里的启发式信息仅基于已经计算好的到T的最短距离,而非传统的启发式估计。它试图找到K条最短路径的总距离。通过记录每个节点被访问的次数cnt[]来控制找到K条路径的目标。

  5. 主函数逻辑:读取输入数据,构建图,执行Dijkstra预处理,然后调用astar()函数并输出结果。利用了优先队列(堆)来实现高效的节点选择。

改进思路

  1. 明确启发式函数:虽然本代码通过Dijkstra预先计算了距离作为启发式的一部分,但在标准A算法中,启发式通常还包括从当前节点到目标的直接估算。此代码实际上更接近于一种特殊目的的多路径查找而非典型的A。若要更贴近A*,可以考虑加入针对S到当前节点的实际启发式估算。

  2. 剪枝和优化:在astar()中,当找到K条路径后立即返回结果可以减少不必要的计算。此外,可以引入更高效的剪枝策略,比如当当前路径的预估总成本超过已找到的K条路径的成本时,停止对该路径的进一步扩展。

  3. 内存和效率:考虑到大型图的应用,可以考虑使用更高效的数据结构来管理优先队列,或者对已访问节点的标记和回溯过程进行优化,以减少内存占用和提高运行速度。

  4. 输入验证和错误处理:增加对输入数据的验证,确保图的有效性,以及处理可能的边界条件和异常情况,提高程序的健壮性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React+TS前台项目实战(二十四)-- 全局常用绘制组件Qrcode封装

文章目录 前言Qrcode组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示(pc端 / 移动端) 总结 前言 今天要封装的Qrcode 组件&#xff0c;是通过传入的信息&#xff0c;绘制在二维码上&#xff0c;可用于很多场景&#xff0c;如区块链项目中的区块显示交易地址时就可以用到…

顶顶通语音信箱手机助手拦截方案(mod_cti基于FreeSWITCH)

文章目录 前言联系我们拦截方案方案一&#xff1a;空号识别拦截拦截时间原理能够识别出的状态 方案二&#xff1a;实时质检拦截拦截时间原理拦截效果展示 服务器配置要求 前言 顶顶通拥有两种语音信箱手机助手拦截方案&#xff1a; 方案一&#xff1a;空号识别拦截&#xff0…

springboot接口防抖【防重复提交】

什么是防抖 所谓防抖&#xff0c;一是防用户手抖&#xff0c;二是防网络抖动。在Web系统中&#xff0c;表单提交是一个非常常见的功能&#xff0c;如果不加控制&#xff0c;容易因为用户的误操作或网络延迟导致同一请求被发送多次&#xff0c;进而生成重复的数据记录。要针对用…

成都百洲文化传媒有限公司电商服务的佼佼者

在当今这个数字化时代&#xff0c;电商已成为商业发展的核心动力之一。成都百洲文化传媒有限公司&#xff0c;作为一家专注于电商服务的领先企业&#xff0c;正以其卓越的服务质量和前瞻性的战略眼光&#xff0c;引领着电商行业的新潮流。 一、公司简介 成都百洲文化传媒有限公…

sssssssssssssssshare_ptrrrrrrrrrrrrrrrrrrrrrrrrr

智能指针——shared_ptr的原理及仿写 shared_ptr的原理及仿写 共享指针允许多个指针指向同一份数据&#xff0c;因为它使用了引用计数&#xff0c;每多一个指针指向这个数据&#xff0c;引用技术加一&#xff0c;每销毁一个指针&#xff0c;引用技术减一&#xff0c;如果引用计…

拓展欧几里得和裴蜀定理

裴蜀定理&#xff08;或贝祖定理&#xff09;说明了对任何整数a、b和它们的最大公约数d&#xff0c;关于未知数x和y的线性不定方程&#xff08;称为裴蜀等式&#xff09;&#xff1a;若a,b是整数,且gcd(a,b)d&#xff0c;那么对于任意的整数x,y,axby都一定是d的倍数&#xff0c…

【安全攻防】网络安全中的序列化与反序列

1.序列化与反序列化 首先要了解序列化与反序列化的定义&#xff0c;以及序列化反序列化所用到的基本函数。 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化&#xff0c;相当于游戏中的存档。 PHP中的序列化函数serialize() **serialize()**函数用于序列化对…

jsqlparse工具拦截sql处理和拓展

前置知识 访问者模式 &#xff08;Visitor Pattern&#xff09;是一种行为设计模式&#xff0c;它允许你定义在不改变被访问元素的类的前提下&#xff0c;扩展其功能。通过将操作&#xff08;操作或算法&#xff09;从对象结构中提取出来&#xff0c;可以在不修改这些对象的前…

6.基于SpringBoot的SSMP整合案例-业务层开发

目录 1.业务层标准开发 1.1接口定义 1.2实现类定义 1.3测试类定义 1.4小结&#xff1a; 2.业务层快速开发 2.1使用MyBatisP1us提供有业务层通用接口(ISerivce)与业务层通用实现类(ServiceImpl),t> 接口定义&#xff1a; 实现类定义&#xff1a; 测试类&#xff1a; …

MergeBus封装模块

当模型有很多信号进行交互的时候&#xff0c;并且已经无法回避线条交叉的时候&#xff0c;我们会选择 From和Goto模块来提高模型的可读性&#xff0c;假如你拿到的模型如下图&#xff1a; 像不像芯片的电路&#xff0c;错综而复杂 该如何整理呢&#xff1f; 我相信有很多模型…

2024年移动手游趋势:休闲类手游收入逆势增长,欧美玩家成为主力

移动手游广告情报平台Sensor Tower近期发布的报告显示&#xff0c;从宏观数据来看&#xff0c;尽管2023年对于移动游戏市场来说是艰难的一年&#xff0c;无论是总下载量亦或是总收入都较去年有所下降&#xff0c;尤其是Google Play。但在总体下降的大趋势下&#xff0c;休闲游戏…

mac如何压缩视频大小不改变画质,mac怎么压缩视频软件

在数字时代&#xff0c;视频已成为信息传递和娱乐消遣的重要媒介。然而&#xff0c;视频带来的愉悦体验背后&#xff0c;是日益增长的存储和分享压力。大视频文件不仅占用大量存储空间&#xff0c;上传和下载也变得异常缓慢。那么&#xff0c;如何才能有效压缩视频&#xff0c;…

SAP中的 UPDATA TASK 和 BACKGROUND TASK

前言&#xff1a; 记录这篇文章起因是调查生产订单报工问题引申出来的一个问题&#xff0c;后来再次调查后了解了其中缘由&#xff0c;大概记录以下&#xff0c;如有不对&#xff0c;欢迎指正。问题原贴如下&#xff1a; SAP CO11N BAPI_PRODORDCONF_CREATE_TT连续报工异步更…

LoadRunner-Virtual User Generator组件学习(录制不上内容)

重点知识 LR工具是拿C写的&#xff0c;所以它的脚本默认也是C&#xff0c;但是最终生成的脚本不止是C&#xff0c;它是支持C和Java语言的&#xff0c;这个大家要清楚&#xff0c;对本身懂代码的就很友好&#xff0c;你了解java&#xff0c;那就可以把脚本改成java&#xff0c;…

不看后悔!国内AI大比拼的精彩看点全汇总

至2022年AI爆发后&#xff0c;在中国已催生了上千个AI产品。 这些产品涵盖了从头部大厂到高等院校&#xff0c;再到初创企业的广泛阵容。 如&#xff1a; 大厂&#xff1a;百度文心、阿里通义、腾讯元宝、字节豆包、讯飞星火等高校&#xff1a;清华大学、北京大学等初创&…

.NET 漏洞分析 | 某ERP系统存在SQL注入

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

JAVA导出数据库字典到Excel

文章目录 1、查询某张表字段信息2、TableVo接收sql查询得到的数据3、excel导出4、导出案例 1、查询某张表字段信息 select column_name as columnName, -- 字段名 COLUMN_DEFAULT as colDefault, -- 默认值 column_key as columnKey, -- PRI-主键&#xff0c;UNI-唯一键&…

机器学习原理之 -- 朴素贝叶斯分类器:由来及原理详解

朴素贝叶斯&#xff08;Naive Bayes&#xff09;分类器是一类基于贝叶斯定理&#xff08;Bayes Theorem&#xff09;的简单而有效的概率分类算法。由于其假设特征之间的条件独立性&#xff0c;因此被称为“朴素”贝叶斯分类器。尽管这种独立性假设在现实中很少完全成立&#xf…

VSCode使用ipynb文件高效地进行功能测试

一、ipynb是什么文件 .ipynb文件是Jupyter Notebook的专用格式&#xff0c;它允许用户在一个网页应用中混合编写Markdown文本、执行代码、查看输出结果及图表。Jupyter Notebook的本质是一个Web应用程序&#xff0c;支持运行40多种编程语言&#xff0c;包括Python。它的主要用…