A*——AcWing 179. 八数码

news2024/11/25 18:49:38

A*

定义

A* 算法是一种在图形或地图中寻找最短路径的启发式搜索算法。它通过综合考虑起始节点到当前节点的实际代价和当前节点到目标节点的预估代价,来决定下一步的搜索方向。

运用情况

  • 路径规划:如在地图导航中为车辆、行人规划最优路线。
  • 游戏开发:例如在策略游戏中为角色寻找到达目标的最短路径。
  • 机器人导航:帮助机器人在复杂环境中找到高效的移动路径。

注意事项

  • 启发函数的设计:启发函数的准确性对算法的效率和结果质量有很大影响。如果启发函数过于乐观或悲观,可能导致算法找不到最优解或效率低下。
  • 内存使用:在处理大规模的地图或图形时,A* 算法可能需要大量的内存来存储已访问和待访问的节点信息。
  • 优化策略:需要根据具体问题选择合适的优化策略,如双向搜索、限制搜索区域等。

解题思路

  1. 初始化:将起始节点放入开放列表,设置其代价。
  2. 循环:
    • 从开放列表中选择代价最小的节点作为当前节点。
    • 将当前节点移出开放列表,放入关闭列表。
    • 对当前节点的相邻节点进行处理:
      • 如果相邻节点在关闭列表中,忽略。
      • 如果不在开放列表中,计算其代价并放入开放列表。
      • 如果在开放列表中,更新其代价,如果新代价更小则更新其父节点。
  3. 直到目标节点被放入关闭列表,或者开放列表为空(未找到路径)。

例如,在地图导航中,起始节点是你的当前位置,目标节点是你的目的地。每个节点代表地图上的一个位置,节点之间的连接表示可能的路径。通过不断评估每个可能的下一步路径的代价,A* 算法能够快速找到从起始点到目标点的最短路径。

A 算法的优缺点*:

优点:

  1. 高效性:通常能够在合理的时间内找到较优的解,特别是在地图规模不是特别巨大的情况下。
  2. 最优性保证:在启发函数估计准确的前提下,能够找到最优解。
  3. 灵活性:可以应用于各种不同类型的图和问题领域,只要能够定义合适的代价函数和启发函数。
  4. 易于理解和实现:其基本思想相对直观,实现起来并不复杂。

例如,在城市交通导航中,A* 算法能够快速为司机规划出一条相对较短且高效的行驶路线,节省时间和燃油。

缺点:

  1. 启发函数的依赖:启发函数的质量对算法性能影响极大,如果启发函数设计不好,可能导致算法效率低下或找不到最优解。
  2. 内存消耗:在处理大规模的问题时,可能需要大量的内存来存储节点信息和搜索过程中的数据。
  3. 计算开销:计算每个节点的代价和启发值需要一定的计算资源。
  4. 对复杂环境的适应性有限:在某些极端复杂或动态变化的环境中,可能表现不佳。

比如,在一个实时变化的物流配送网络中,由于路况等因素不断变化,A* 算法可能难以快速适应并重新规划最优路径。

常用的路径规划算法

Dijkstra 算法
这是一种用于求解图中单个源点到其他所有顶点的最短路径的算法。它会遍历所有可能的路径,逐步更新节点的最短距离,直到找到所有节点的最短路径。优点是能保证找到最短路径,缺点是计算量较大,效率相对较低。

例如,在物流配送中心规划送货路线时,如果只关注从配送中心到各个目的地的最短距离,Dijkstra 算法就可以适用。

Floyd-Warshall 算法
用于计算图中所有顶点对之间的最短路径。通过动态规划的思想,逐步更新任意两点之间的最短距离。该算法的优点是可以一次性得到所有点对之间的最短路径,缺点是时间和空间复杂度较高。

比如,在分析多个城市之间的最优交通连接时,Floyd-Warshall 算法可以提供全面的路径信息。

蚁群算法
模拟蚂蚁在寻找食物过程中的行为来寻找最优路径。蚂蚁会根据路径上的信息素浓度选择路径,同时在经过的路径上留下信息素,使得后续的蚂蚁更倾向于选择较优的路径。优点是具有较强的全局搜索能力和自适应性,缺点是计算时间可能较长,参数设置较复杂。

在大规模的网络路由规划中,蚁群算法可以发现复杂网络中的优质路径。

粒子群优化算法
通过模拟鸟群觅食的行为来寻找最优解。粒子在解空间中移动,根据自身和群体的历史最优位置来更新自己的位置。优点是实现简单,收敛速度较快,缺点是容易陷入局部最优。

例如,在无人机的自主飞行路径规划中,可以使用粒子群优化算法来找到合适的路线。

遗传算法
基于生物进化的思想,通过选择、交叉和变异等操作来优化解。优点是能够处理复杂的优化问题,具有较好的全局搜索能力,缺点是计算量较大,编码和解码过程可能较复杂。

比如,在机器人在复杂环境中的路径规划问题中,遗传算法可以发挥作用。

AcWing 179. 八数码

题目描述

AcWing 179. 八数码 - AcWing

运行代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
typedef pair<int, string> PIS;
int f(string state)
{
    int res = 0;
    for(int i = 0; i < state.size(); i ++ )
        if(state[i] != 'x')
        {
            int t = state[i] - '1';
            res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
        }
    return res;
}
string bfs(string start)
{
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
    char op[4] = {'u', 'r', 'd', 'l'};
    string end = "12345678x";
    unordered_map<string, int> dist;
    unordered_map<string, pair<string, char>> prev;
    priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
    heap.push({f(start), start});
    dist[start] = 0;
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();
        string state = t.second;
        if(state == end) break;
        int step = dist[state];
        int x, y;
        for(int i = 0; i < state.size(); i ++ )
            if(state[i] == 'x')
            {
                x = i / 3, y = i % 3;
                break;
            }
        string scource = state;
        for(int i = 0; i < 4; i ++ )
        {
            int a = x + dx[i], b = y + dy[i];
            if(a >= 0 && a <= 2 && b >= 0 && b <= 2)
            {
                swap(state[x * 3 + y], state[a * 3 + b]);
                if(!dist.count(state) || dist[state] > step + 1)
                {
                    dist[state] = step + 1;
                    prev[state] = {scource, op[i]};
                    heap.push({dist[state] + f(state), state});
                }
                swap(state[x * 3 + y], state[a * 3 + b]);
            }
            
        }
    }
    string res;
    while(end != start)
    {
        res += prev[end].second;
        end = prev[end].first;
    }
    reverse(res.begin(), res.end());
    return res;
}
int main()
{
    string g, c, seq;
    while(cin >> c)
    {
        g += c;
        if(c != "x") seq += c;
    }
    int res = 0;
    for(int i = 0; i < seq.size(); i ++ )
        for(int j = i + 1; j < seq.size(); j ++ )
            if(seq[i] > seq[j]) res ++ ;
    if(res & 1) puts("unsolvable");
    else cout << bfs(g) << endl;
    return 0;
}

代码思路

  1. f 函数用于计算一个状态与目标状态的曼哈顿距离估计值,作为启发函数。
  2. bfs 函数实现了广度优先搜索来求解八数码问题的最优路径。
    • 定义了移动方向和对应的操作字符。
    • 使用优先队列进行搜索,根据当前状态的步数和启发函数值进行排序。
    • 通过遍历四个方向,尝试交换空白格与相邻位置的数字,更新状态和相关信息。
    • 最终通过回溯得到从起始状态到目标状态的路径。
  3. main 函数用于读取输入的八数码状态,判断是否可解,并调用 bfs 函数求解。

改进思路

  1. 数据结构优化:考虑使用更高效的数据结构来存储已访问的状态,例如布隆过滤器或者哈希表的优化实现,以提高查找速度。
  2. 启发函数改进:进一步优化启发函数,使其更准确地估计到目标状态的距离,可能会提高搜索效率。
  3. 剪枝策略:分析问题的特性,添加更多有效的剪枝条件,避免不必要的搜索。
  4. 并行化:如果计算资源允许,可以考虑对搜索过程进行并行化处理,加快搜索速度。
  5. 代码可读性和可维护性:添加更多的注释来解释关键代码段的作用和逻辑。将一些复杂的逻辑提取为独立的函数,以提高代码的可读性和可维护性。

其它代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
typedef pair<int, string> PIS;
int f(string state) {
    int res = 0;
    for (int i = 0; i < state.size(); i++)
        if (state[i]!= 'x') {
            int t = state[i] - '1';
            res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
        }
    return res;
}
string bfs(string start) {
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
    char op[4] = {'u', 'r', 'd', 'l'};
    string end = "12345678x";
    unordered_map<string, int> dist;
    unordered_map<string, pair<string, char>> prev;
    priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
    heap.push({f(start), start});
    dist[start] = 0;
    while (heap.size()) {
        auto t = heap.top();
        heap.pop();
        string state = t.second;
        if (state == end) break;
        int step = dist[state];
        int x, y;
        for (int i = 0; i < state.size(); i++)
            if (state[i] == 'x') {
                x = i / 3, y = i % 3;
                break;
            }
        string scource = state;
        for (int i = 0; i < 4; i++) {
            int a = x + dx[i], b = y + dy[i];
            if (a >= 0 && a <= 2 && b >= 0 && b <= 2) {
                swap(state[x * 3 + y], state[a * 3 + b]);
                if (!dist.count(state) || dist[state] > step + 1) {
                    dist[state] = step + 1;
                    prev[state] = {scource, op[i]};
                    heap.push({dist[state] + f(state), state});
                }
                swap(state[x * 3 + y], state[a * 3 + b]);
            }
        }
    }
    string res;
    while (end!= start) {
        res += prev[end].second;
        end = prev[end].first;
    }
    reverse(res.begin(), res.end());
    return res;
}

int main() {
    string g, c, seq;
    while (cin >> c) {
        g += c;
        if (c!= "x") seq += c;
    }
    int res = 0;
    for (int i = 0; i < seq.size(); i++)
        for (int j = i + 1; j < seq.size(); j++)
            if (seq[i] > seq[j]) res++;
    if (res & 1) puts("unsolvable");
    else cout << bfs(g) << endl;
    return 0;
}

代码思路

  • f 函数用于计算当前状态与目标状态的曼哈顿距离估计值。
  • bfs 函数通过广度优先搜索和优先队列来找到从初始状态到目标状态的最优路径。
    • 定义了移动方向和对应的操作字符。
    • 维护了已访问状态的距离和前驱信息。
    • 通过交换 x 与相邻位置的数字来探索新状态。
  • main 函数读取输入的初始状态,判断其是否可解,然后调用 bfs 函数求解并输出结果。

改进思路

  • 可以考虑使用位运算来表示状态,减少存储空间和计算量。
  • 对于启发函数,可以进一步研究更精确的估计方式。
  • 对搜索过程中的一些边界情况和异常处理进行更完善的考虑。

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

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

相关文章

【附精彩文章合辑】佛光普照,智慧引领——记首个中文社区版Gemma-2的诞生,共筑和谐科技净土

阿弥陀佛&#xff0c;贫僧唐僧&#xff0c;自西天取经归来&#xff0c;虽已超脱尘世&#xff0c;然心系众生&#xff0c;尤是见科技日新月异&#xff0c;信息洪流浩渺无垠&#xff0c;心中不免生出几分感慨与期许。近日&#xff0c;闻讯首个中文社区版的Gemma-2即将面世&#x…

【Pyhton学习】常用标识符与关键字

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 1. 标识符与关键字2. 常用格式化输出符号3. 算数运算符4. 赋值运算符5. 比较运算符总结 1. 标识符与关键字 在Python…

桌面记笔记的软件:能加密的笔记app

在日常生活和工作中&#xff0c;很多人都有记笔记的习惯。无论是记录会议要点、学习心得&#xff0c;还是生活中的点滴灵感&#xff0c;笔记都是我们不可或缺的好帮手。然而&#xff0c;传统的纸笔记录方式逐渐不能满足现代人的需求&#xff0c;因为纸质笔记不易保存、查找困难…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-39实战Kaggle比赛:狗的品种识别(ImageNet Dogs)

39实战Kaggle比赛&#xff1a;狗的品种识别&#xff08;ImageNet Dogs&#xff09; 比赛链接&#xff1a;Dog Breed Identification | Kaggle 1.导入包 import torch from torch import nn import collections import math import os import shutil import torchvision from…

nacos开启鉴权后,springboot注册失败

1.确认Nacos版本 我的Nacos版本是1.4.2 2.确认Nacos相关依赖的版本之间兼容&#xff0c;一下是我的一些pom.xml依赖 <!--父级项目的--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifa…

MySQL:MySQL总结

文章目录 MySQL思维导图基础实际在 Innodb 存储引擎中&#xff0c;会用一个特殊的记录来标识最后一条记录&#xff0c;该特殊的记录的名字叫 supremum pseudo-record &#xff0c;所以扫描第二行的时候&#xff0c;也就扫描到了这个特殊记录的时候&#xff0c;会对该主键索引加…

深化产教融合“桥梁”作用!蓝卓携手宁波4大院校共育数智人才

建强“三支队伍”赋能新质生产力&#xff0c;为进一步加强新时代教师队伍建设改革&#xff0c;促进人才培养能力和服务企业能力“双提升”&#xff0c;7月2日&#xff0c;“2024企业实践工业互联网职业教育师资培训班”在蓝卓顺利开班。 来自宁波城市职业技术学院、宁波职业技…

代理IP和VPN有什么区别?该怎么选择?

今天我们来聊聊很多人关心的一个问题——代理IP和VPN到底有什么区别&#xff1f;虽然它们听起来差不多&#xff0c;但其实有很大的不同。这篇文章&#xff0c;小编就带大家一起了解一下吧&#xff01; 什么是代理IP&#xff1f; 代理IP是一种通过代理服务器替换用户真实IP地址…

c进阶篇(四):内存函数

内存函数以字节为单位更改 1.memcpy memcpy 是 C/C 中的一个标准库函数&#xff0c;用于内存拷贝操作。它的原型通常定义在 <cstring> 头文件中&#xff0c;其作用是将一块内存中的数据复制到另一块内存中。 函数原型&#xff1a;void *memcpy(void *dest, const void…

UE5 修改项目名称 类的名称

修改类的名称 这里推荐使用Rider编辑器修改&#xff0c;它会给你遍历所有的引用&#xff0c;然后一次性修改&#xff0c;并自动添加DefaultEngine.ini。接下来&#xff0c;我将给大家演示如何实现。 我们在一个类的文件上面选择重构此 然后选择重命名 在弹框内修改为新的名称…

PG实践|内置函数之GENERATE_SERIES之深入理解(二)

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

【Whisper】WhisperX: Time-Accurate Speech Transcription of Long-Form Audio

Abstract Whisper 的跨语言语音识别取得了很好的结果&#xff0c;但是对应的时间戳往往不准确&#xff0c;而且单词级别的时间戳也不能做到开箱即用(out-of-the-box). 此外&#xff0c;他们在处理长音频时通过缓冲转录

c++类模板--无法解析的外部符号

解决办法 文章目录 解决办法方法1(推荐).在主函数包含头文件时将实现模板类的函数也包含进来方法2.将模板类的实现方法写在头文件里面方法3.函数模板声明前加inline 可能错误2&#xff0c;类内实现友元输出重载 方法1(推荐).在主函数包含头文件时将实现模板类的函数也包含进来 …

七、函数练习

目录 1. 写一个函数可以判断一个数是不是素数。&#xff08;素数只能被1或其本身整除的数&#xff09; 2. 一个函数判断一年是不是闰年。 3.写一个函数&#xff0c;实现一个整形有序数组的二分查找。 4. 写一个函数&#xff0c;每调用一次这个函数&#xff0c;使得num每次增…

养老院人员定位系统如何实现

养老院人员定位系统应反应养老公寓情况、增加老人安全防范级别、加强安全保障措施&#xff0c;部署物联网设备及配套集成平台软件&#xff0c;实时定位人员信息及时反应老人救助行为&#xff0c;实现与视频、门禁一卡通等自动化监管设施联合动作&#xff0c;提高应急响应速度和…

【vite创建项目】

搭建vue3tsvitepinia框架 一、安装vite并创建项目1、用vite构建项目2、配置vite3、找不到模块 “path“ 或其相对应的类型声明。 二、安装element-plus1、安装element-plus2、引入框架 三、安装sass sass-loader1、安装sass 四、安装vue-router-next 路由1、安装vue-router42搭…

Mybatis入门の基础操作

1 Mybatis概述 MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解&#xff0c;将接口和 Java 的 POJOs(Plain Old Java Objects,普通的…

vue3+vue-router+vite 实现动态路由

文章中出现的代码是演示版本&#xff0c;仅供参考&#xff0c;实际的业务需求会更加复杂 什么是动态路由 什么场景会用到动态路由 举一个最常见的例子&#xff0c;比如说我们要开发一个后台管理系统&#xff0c;一般来说后台管理系统都会分角色登录&#xff0c;这个时候也就涉…

幻兽帕鲁卡顿严重、延迟高怎么办?幻兽帕鲁卡顿问题处理

幻兽帕鲁更是一款支持多人游戏模式的生存制作游戏。玩家们可以邀请好友一同加入这个充满奇幻与冒险的世界&#xff0c;共同挑战强大的敌人&#xff0c;分享胜利的喜悦。在多人模式中&#xff0c;玩家之间的合作与竞争将成为游戏的一大看点。玩家们需要充分发挥自己的智慧和策略…

centos7的yum命令无法使用解决方案

文章目录 问题排查流程解决方案总结 问题 今天新建了个centos7的虚拟机发现yum无法正常使用 已加载插件&#xff1a;fastestmirror Determining fastest mirrors Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archx86_64&repoos&infra…