c++ A*搜索算法

算法原理

A*算法通过以下公式计算节点的优先级:

f(n)=g(n)+h(n)
  • f(n):节点 n的总优先级,表示从起点通过节点 n 到目标点的估计代价。
  • g(n):从起点到节点 n 的实际代价。
  • h(n):从节点 n到目标点的启发式估计代价。

A*的核心是选择具有最低 f(n)值的节点进行扩展,从而在保证正确性的同时提高效率。

启发函数(Heuristic Function)

启发函数 h(n)决定了算法的效率和准确性:

  • 一致性(Consistency):如果 h(n)满足三角不等式,即 h(n)≤c(n,n′)+h(n′),算法可以保证最优性。

  • 常用启发函数:

    • 曼哈顿距离(适用于网格地图):
    h(n)=∣x1−x2∣+∣y1−y2∣
    
    • 欧几里得距离(适用于几何地图):

    在这里插入图片描述

    • 自定义启发函数:针对特定场景设计的函数。

算法流程

初始化

  • 将起点加入开放列表(Open List)。
  • 关闭列表(Closed List)为空。

迭代搜索

  1. 从开放列表中选择 f(n)最小的节点 n。
  2. 如果 n 是目标节点,终止并返回路径。
  3. 将 n 从开放列表移除,并加入关闭列表。
  4. 扩展节点 n 的所有邻居节点:
    • 如果邻居不在关闭列表中:
      • 计算邻居的 g(n)、h(n)和 f(n)。
      • 如果邻居不在开放列表中,将其加入开放列表。
      • 如果邻居已在开放列表中且新的 g(n) 更优,更新邻居的值。

返回结果

  • 如果开放列表为空,表示无解。
  • 否则返回路径。

代码实现

#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <unordered_map>
using namespace std;

// 定义网格节点
struct Node {
    int x, y;           // 坐标
    double g, h, f;     // 代价
    Node* parent;       // 父节点

    Node(int x, int y, double g = 0, double h = 0, Node* parent = nullptr)
        : x(x), y(y), g(g), h(h), f(g + h), parent(parent) {}

    bool operator>(const Node& other) const {
        return f > other.f; // 优先队列按 f 值排序
    }
};

// 启发函数:曼哈顿距离
double heuristic(int x1, int y1, int x2, int y2) {
    return abs(x1 - x2) + abs(y1 - y2);
}

// 检查点是否在网格内
bool isValid(int x, int y, int rows, int cols) {
    return x >= 0 && x < rows && y >= 0 && y < cols;
}

// A* 搜索
vector<pair<int, int>> aStarSearch(vector<vector<int>>& grid, pair<int, int> start, pair<int, int> goal) {
    int rows = grid.size();
    int cols = grid[0].size();

    priority_queue<Node, vector<Node>, greater<Node>> openList; // 最小堆
    unordered_map<int, bool> closedList; // 关闭列表(标记访问的点)

    auto encode = [&](int x, int y) { return x * cols + y; }; // 坐标哈希

    // 初始节点
    Node* startNode = new Node(start.first, start.second, 0, heuristic(start.first, start.second, goal.first, goal.second));
    openList.push(*startNode);

    // 定义方向向量
    vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    while (!openList.empty()) {
        Node current = openList.top();
        openList.pop();

        // 检查是否到达目标
        if (current.x == goal.first && current.y == goal.second) {
            vector<pair<int, int>> path;
            Node* temp = &current;
            while (temp) {
                path.emplace_back(temp->x, temp->y);
                temp = temp->parent;
            }
            reverse(path.begin(), path.end());
            return path;
        }

        // 标记当前点为访问过
        closedList[encode(current.x, current.y)] = true;

        // 扩展邻居节点
        for (auto& dir : directions) {
            int nx = current.x + dir.first;
            int ny = current.y + dir.second;

            if (isValid(nx, ny, rows, cols) && grid[nx][ny] == 0 && !closedList[encode(nx, ny)]) {
                double g = current.g + 1; // 假设代价为1
                double h = heuristic(nx, ny, goal.first, goal.second);
                openList.push(Node(nx, ny, g, h, new Node(current.x, current.y, current.g, current.h, current.parent)));
            }
        }
    }

    return {}; // 无解
}

int main() {
    vector<vector<int>> grid = {
        {0, 0, 0, 0, 0},
        {0, 1, 1, 1, 0},
        {0, 0, 0, 1, 0},
        {0, 1, 0, 0, 0},
        {0, 0, 0, 0, 0},
    };

    pair<int, int> start = {0, 0};
    pair<int, int> goal = {4, 4};

    vector<pair<int, int>> path = aStarSearch(grid, start, goal);

    if (!path.empty()) {
        cout << "Path found:\n";
        for (auto& p : path) {
            cout << "(" << p.first << ", " << p.second << ") -> ";
        }
        cout << "Goal\n";
    } else {
        cout << "No path found.\n";
    }

    return 0;
}

时间复杂度

  • 最坏情况:O(E),其中 E 是图的边数。
  • 在稀疏图中效率较高,常结合优化数据结构(如 Fibonacci 堆)提升性能。

应用场景

  • 地图导航(如 Google Maps)。
  • 游戏 AI 路径规划。
  • 机器人路径规划。

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

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

相关文章

修理一个433Mhz遥控器无法遥控和接触不良的故障

修了一个遥控器&#xff0c;故障表现为其中一个硅胶按键接触不良&#xff0c;使劲按压&#xff0c;却是时而可以时而无法遥控。另外一个为完全无法遥控。 按键部分图示如下 用频谱看&#xff0c;能发射的遥控器发出430Mhz的信号&#xff0c;虽然有接触不良&#xff0c;但是可以…

RabbitMQ 客户端工程环境配置

RabbitMQ 客户端工程环境配置 下面分别以 C# 控制台应用程序 、 Unity 工程为例 一 C# 控制台应用程序 &#xff08;1&#xff09;新建项目 (2) RabbitMQ 需要通过 NuGet 安装 打开项目解决方案 -> 依赖项(右键) -> 管理 NuGet 程序包 -> 搜索 RabbitMQ.Client -&…

Flutter | 基于函数式编程的通用单选列表设计

背景 项目中多次用到如下图的通用单选列表页&#xff1a; 常规封装 此列表需要三样东西&#xff1a; 标题数组当前选中项的 index点击 cell 的回调 封装大体如下&#xff1a; import package:flutter/material.dart;class ListPage1 extends StatefulWidget {const ListPa…

使用Python OpenCV实现图像形状检测

目录 一、环境准备 二、读取和预处理图像 读取图像 灰度化 滤波去噪 三、边缘检测 四、查找轮廓 五、绘制轮廓 六、形状分类 七、显示结果 八、完整代码示例 九、总结 图像形状检测是计算机视觉领域中的一项关键技术,广泛应用于工业自动化、机器人视觉、医学图像处…

ffmpeg 增亮 docker 使用

使用最新的 docker pull jrottenberg/ffmpeg docker run -it --rm -v /path/to/input:/input -v /path/to/output:/output jrottenberg/ffmpeg <ffmpeg command>比如我想增亮 在 /home 目录下 有一个 video.mp4 docker run --rm -v /home:/home jrottenberg/ffmpeg:7…

C与指针。

目录 1_指针理解 1.1变量的值 1.2变量的地址 1.3指针 1.4取变量的地址 2_分析指针 2.1分析指针变量的要素 2.2根据需求定义指针变量 3_指针的使用 3.1指针对变量的读操作 3.2指针对变量的写操作 4_指针占用空间的大小与位移 4.1指针占用空间的大小 4.2指针的位移…

算法与数据结构(1)

一&#xff1a;数据结构概论 数据结构分为初阶数据结构&#xff08;主要由C语言实现&#xff09;和高阶数据结构&#xff08;由C实现&#xff09; 初阶数据结构当中&#xff0c;我们会学到顺序表、链表、栈和队列、二叉树、常见排序算法等内容。 高阶数据结构当中&#xff0…

Oracle12.2 RAC集群管理修改IP地址(DNS解析)

Oracle12.2 RAC集群管理之修改IP地址 该章节实验是基于此章节基础上操作&#xff1a; Oracle LinuxR7安装Oracle 12.2 RAC集群实施&#xff08;DNS解析&#xff09;-CSDN博客 环境 改前IP&#xff1a; 172.30.21.101 hefei1 hefei1.hefeidb.com 172.30.21.102 hefei2 …

【阅读笔记】Android广播的处理流程

关于Android的解析&#xff0c;有很多优质内容&#xff0c;看了后记录一下阅读笔记&#xff0c;也是一种有意义的事情&#xff0c; 今天就看看“那个写代码的”这位大佬关于广播的梳理&#xff0c; https://blog.csdn.net/a572423926/category_11509429.html https://blog.c…

基于rpcapd与wireshark的远程实时抓包的方法

基于rpcapd与wireshark的远程实时抓包的方法 服务端安装wireshark侧设置 嵌入式设备或服务器上没有图形界面&#xff0c;通常使用tcpdump抓包保存为pcap文件后&#xff0c;导出到本地使用wireshark打开分析&#xff0c;rpcapd可与wireshark配合提供一种远程实时抓包的方案&…

SpringBoot3如何基于ServletRequestHJandledEvent检测接口响应时间以及对应的参数

在 Spring Boot 3 中&#xff0c;可以通过实现 ServletRequestHandledEvent 事件来监测接口的响应时间以及相关的参数。ServletRequestHandledEvent 是 Spring 的应用事件之一&#xff0c;它在请求处理完成时发布&#xff0c;包含有关请求的信息。 以下是一个步骤指南&#xff…

MyBatis快速入门(中)

MyBatis快速入门&#xff08;中&#xff09; 四、全局配置文件configuration标签中子标签顺序1、子标签顺序2、子标签说明3、<properties> 标签和 <environments> 标签详述4、配置文件代码示例 五、MyBatis 基础功能之 resultMap1、建表语句2、解决表中字段名和类中…

【热门主题】000069 服务器虚拟化:开启高效资源管理新时代

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

day22:lamp项目部署

一&#xff0c;lamp概述 lamp概述 LAMP 是一组开源软件的缩写&#xff0c;用于搭建动态网站或Web应用程序的基础环境。LAMP 代表了四个主要的组成部分&#xff1a; Linux&#xff1a;操作系统&#xff0c;LAMP 环境的基础。通常使用的是 Linux 发行版&#xff0c;如 CentOS、…

通俗易懂:序列标注与命名实体识别(NER)概述及标注方法解析

目录 一、序列标注&#xff08;Sequence Tagging&#xff09;二、命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&#xff09;**命名实体识别的作用****命名实体识别的常见实体类别** &#xff1a; 三、标签类型四、序列标注的三种常见方法1. **BIO&#xf…

01-Ubuntu24.04LTS上安装PGSQL

目录 一、准备工作 1.1、系统要求 1.2 、更新 Ubuntu 系统 1.3 、安装依赖 1.4 、添加 PostgreSQL 16 软件源 二、安装 PostgreSQL 16 数据库 三、管理 PostgreSQL 服务 四、PostgreSQL 管理操作 4.1 、访问 Postgres 超级用户账户 4.2 、创建数据库并设置管理权限 4…

利用阿里云镜像仓库和 Github Action 同步镜像

利用阿里云镜像仓库和 Github Action 同步镜像 由于某些未知原因,国内无法直接从 DockerHub 拉取镜像,在不使用 VPN 等违法工具的情况下,可以利用 GitHub 的 Action 流水线功能,将镜像推送到阿里云的个人镜像仓库中。 这种方式相较于其他方式虽然相对麻烦,但好在免费,且实…

iOS与Windows间传文件

想用数据线从 windows 手提电脑传文件入 iPhone&#xff0c;有点迂回。 参考 [1]&#xff0c;要在 windows 装 Apple Devices。装完、打开、插线之后会检测到手机&#xff0c;界面&#xff1a; 点左侧栏「文件」&#xff0c;不是就直接可以传&#xff0c;而是要通过某个应用传…

如何使用Python解析从淘宝API接口获取到的JSON数据?

基本的 JSON 解析 当从淘宝 API 接口获取到数据后&#xff08;假设数据存储在变量response_data中&#xff09;&#xff0c;首先要判断数据类型是否为 JSON。如果是&#xff0c;就可以使用 Python 内置的json模块进行解析。示例代码如下&#xff1a; import json # 假设respon…

Cesium K-means自动聚合点的原理

Cesium K-means自动聚合点的原理 Cesium 是一个开源的 JavaScript 库&#xff0c;用于在 Web 环境中创建 3D 地球和地图应用。它能够处理地理空间数据&#xff0c;并允许开发者对大规模的地理数据进行可视化展示。在一些应用中&#xff0c;尤其是当处理大量地理坐标点时&#…