A*搜索算法 双向A*搜索算法 Julia实现

news2025/1/17 23:06:17

算法概述

抽象的在非负有向边权图 G = ( V , E , W ) , W : E → R + G = (V, E, W), W: E \to \mathbb{R+} G=(V,E,W),W:ER+ 上的 BFS 过程可以看作这样:
(1) 设 C C C 点集表示已遍历的点, ∀ n ∈ C , d ( n ) \forall n \in C, d(n) nC,d(n) 表示源点 s s s 到点 n n n 的最短距离, O O O 点集表示可遍历的点, ∀ n ∈ O , g ( n ) \forall n \in O, g(n) nO,g(n) 表示源点 s s s 到点 n n n 的当前最短距离,初始状态 C = ∅ , O = { s } , g ( s ) = 0 C = \emptyset, O = \{ s \}, g(s) = 0 C=,O={s},g(s)=0
(2) 从 O O O 中取本轮遍历点 n k n_k nk 满足 n k = arg min ⁡ n ∈ O g ( n ) n_k = \argmin_{n \in O} g(n) nk=argminnOg(n),更新已遍历点集 C = C + { n k } , d ( n k ) = g ( n k ) C = C + \{ n_k \}, d(n_k) = g(n_k) C=C+{nk},d(nk)=g(nk),并更新可遍历点集 O = O − { n k } + { n j ∣ n j n k ∈ E   a n d   n j ∉ C } , ∀ n j ∈ O , g ( n j ) = min ⁡ ∀ n i ∈ C d ( n i ) + W ( n i n j ) O = O - \{ n_k \} + \{ n_j | n_j n_k \in E \ and \ n_j \notin C \}, \forall n_j \in O, g(n_j) = \min_{\forall n_i \in C} d(n_i) + W(n_i n_j) O=O{nk}+{njnjnkE and nj/C},njO,g(nj)=minniCd(ni)+W(ninj)
(3) 迭代 (2) 直到目标点 t ∈ C t \in C tC,此时 d ( t ) d(t) d(t) 必然为最短路径。

启发式搜索策略会设置一个启发函数 h ( n ) h(n) h(n),用来评估点 n n n 到目标点的距离,每轮选择本轮遍历点 n k n_k nk 时,条件改为 n k = arg min ⁡ n ∈ O g ( n ) + h ( n ) n_k = \argmin_{n \in O} g(n) + h(n) nk=argminnOg(n)+h(n),如此一来 BFS 可看作 h ( n ) ≡ 0 h(n) \equiv 0 h(n)0 的特殊情形。

设最优启发函数 h ∗ ( n ) = d ( t ) − d ( n ) h^*(n) = d(t) - d(n) h(n)=d(t)d(n),则可证明 h ( n ) h(n) h(n) 策略有以下两种情形:
(1) ∀ n , h ( n ) ≤ h ∗ ( n ) \forall n, h(n) ≤ h^*(n) n,h(n)h(n),此时得到的结果必然为最短路径,这样的搜索算法称为 A* 搜索;
(2) ∃ n k , h ( n k ) > h ∗ ( n k ) \exist n_k, h(n_k) > h^*(n_k) nk,h(nk)>h(nk),此时得到的结果不一定为最短路径。

问题描述和结果

问题描述:在网格上从源点移动至目标点,有些网格为障碍不可通行,可通行的网格分 0, 2, 4 三种地形代价,移动分为移动到边相邻的网格和对角相邻的网格,移动代价分为 1 和 2 \sqrt{2} 2 ,总代价为源点到目标点经过网格的网格代价(不含源点)和移动代价之和。

代码:

using Plots, Printf
import Base: +, -, sign
struct Sqr2
    x::Int32; y::Int32
end
+(l::Sqr2, r::Sqr2) = Sqr2(l.x + r.x, l.y + r.y)
-(l::Sqr2, r::Sqr2) = Sqr2(l.x - r.x, l.y - r.y)
function sign(z::Sqr2)
    if z.x == 0
        return sign(z.y)
    elseif z.x > 0 && z.y >= 0 || z.x < 0 && z.y <= 0
        return sign(z.x)
    else
        return sign(z.x^2 - 2 * z.y^2) * sign(z.x)
    end
end
value(z::Sqr2) = z.x + z.y * sqrt(2)

function Heap(c)
    dat, rev, tim, T = [], Dict(), Dict(), 0
    cmp(x, y) = c(x, y) == 0 ? tim[x] < tim[y] : c(x, y) < 0
    function dec(k)
        i = rev[k]
        while i > 1
            j = i ÷ 2
            if cmp(dat[j], k)
                break
            end
            dat[i], rev[dat[j]] = dat[j], i
            i = j
        end
        dat[i], rev[k] = k, i
    end
    function ins(k)
        tim[k], T = T, T + 1
        if !haskey(rev, k)
            push!(dat, k); rev[k] = length(dat)
        end
        dec(k)
    end
    function ext()
        i, k, m = 1, dat[end], dat[1]
        pop!(dat); delete!(rev, m); delete!(tim, m)
        n = length(dat)
        while i * 2 <= n
            j = i * 2
            if j + 1 <= n && cmp(dat[j + 1], dat[j])
                j += 1
            end
            if cmp(k, dat[j])
                break
            end
            dat[i], rev[dat[j]] = dat[j], i
            i = j
        end
        if n > 0
            dat[i], rev[k] = k, i
        end
        return m
    end
    return (ins = ins, ext = ext, emp = () -> (length(dat) == 0))
end

struct Node
    l::Tuple{UInt32, UInt32}; r::UInt8
end

function visualize(L, S, T, M)
    ind = 0
    function visbg()
        K = ['#', ' ', '.', ':']
        C = [:grey, :white, "#00B0F0", "#FFC000"]
        C = [c for (k, c) in zip(K, C) if k in M]
        F = Dict('#' => -1, ' ' => 0, '.' => 1, ':' => 2)
        z = [F[i] for i in M]
        heatmap(1 : L[2], 1 : L[1], z, aspect_ratio = 1;
            size = (L[2] * 40, L[1] * 40 + 100), framestyle = :none,
            xlims = (.5, L[2] + .5), ylims = (.5, L[1] + .5), yflip = true,
            colorbar = false, color = C)
        hline!(.5 : (L[1] + .5), color = :black, legend = false)
        vline!(.5 : (L[2] + .5), color = :black, legend = false)
        annotate!([(0, i, text(string(i), 12)) for i = 0 : 5 : L[1]])
        annotate!([(i, 0, text(string(i), 12)) for i = 5 : 5 : L[2]])
        annotate!(S[2], S[1], text("S", 12))
        annotate!(T[2], T[1], text("T", 12))
    end
    function viscene(B, P, f, save::Bool = true)
        visbg()
        C = (:green, :blue, :lightgreen, :lightblue)
        for (n::Node, p::Node) in P
            if B[n.l...] != n.r
                c, l, q = [C[n.r], C[n.r + 2], :pink], (:top, :bottom)[n.r], Node(p.l, 3 - p.r)
                plot!([n.l[2], p.l[2]], [n.l[1], p.l[1]]; color = haskey(P, q) && P[q] == Node(n.l, q.r) ? c[end] : c[2], w = 5)
                annotate!(n.l[2], n.l[1], text((@sprintf "%.2f" value(f(n))), 8, l, c[1]))
            end
        end
        for (n::Node, p::Node) in P
            if B[n.l...] == n.r
                c = C[n.r]
                plot!([n.l[2], p.l[2]], [n.l[1], p.l[1]]; color = c, w = 5)
            end
        end
        if save
            savefig(@sprintf "output\\%03d.png" ind)
            ind += 1
        end
    end
end

function AStar(L, S, T, M, bidirect::Bool = false)
    B::Matrix{UInt8}, D::Dict{Node, Sqr2}, P = fill(0, L), Dict(), Dict()
    function h(n::Node)
        d = abs.([n.l...] - [(T, S)[n.r]...])
        return Sqr2(abs(d[1] - d[2]), minimum(d))
    end
    f(n::Node) = D[n] + h(n)
    H = Heap((x::Node, y::Node) -> sign(f(x) - f(y)) != 0 ? sign(f(x) - f(y)) : sign(D[P[y]] - D[P[x]]))
    s::Node, t::Node = Node(S, 1), Node(T, 2)
    D[s], P[s] = Sqr2(0, 0), s; H.ins(s)
    if bidirect
        D[t], P[t] = Sqr2(0, 0), t; H.ins(t)
    end
    C, V = Dict(' ' => Sqr2(0, 0), '.' => Sqr2(2, 0), ':' => Sqr2(4, 0)), visualize(L, S, T, M)
    path(n::Node) = n.l == P[n].l ? [n.l] : n.r == 1 ? vcat(path(P[n]), n.l) : vcat(n.l, path(P[n]))
    while !H.emp()
        #V(B, P, f)
        i::Node = H.ext()
        if i == Node(T, 1) || B[i.l...] != 0
            s, t = Node(i.l, 1), Node(i.l, 2)
            println(value(D[s] + (bidirect ? D[t] : Sqr2(0, 0))))
            p = bidirect ? vcat(path(s), path(t)) : path(s)
            V(B, P, f, false)
            plot!([y for (x, y) in p], [x for (x, y) in p]; color = :red, w = 5)
            savefig("output.png")
            return true
        end
        B[i.l...] = i.r
        for (dx, dy) in ((0, -1), (1, 0), (0, 1), (-1, 0), (1, -1), (1, 1), (-1, 1), (-1, -1))
            j::Node = Node((i.l[1] + dx, i.l[2] + dy), i.r)
            if j.l[1] in 1 : L[1] && j.l[2] in 1 : L[2] && M[j.l...] != '#'
                d = D[i] + (dx * dy == 0 ? Sqr2(1, 0) : Sqr2(0, 1)) + C[M[(j.l, i.l)[i.r]...]]
                if !haskey(D, j) || sign(D[j] - d) > 0
                    D[j], P[j] = d, i; H.ins(j)
                end
            end
        end
    end
    return false
end

function input(filename)
    open(filename) do file
        n = map(s -> parse(Int, s), split(readline(file)))
        lines = readlines(file)
        L, S, T = (n[1], n[2]), (n[3], n[4]), (n[5], n[6])
        M = fill(' ', L)
        for i = 1 : L[1]
            M[i, :] = collect(lines[i])
        end
        return L, S, T, M
    end
end

@time f = AStar(input("sample1.txt")...)
@time f = AStar(input("sample1.txt")..., true)
@time f = AStar(input("sample2.txt")...)
@time f = AStar(input("sample2.txt")..., true)

地图以文件形式给出。

Sample 1

sample1.txt

14 17 9 4 10 15
                 
                 
                 
                 
                 
      #          
      #          
       #         
       #         
       ##        
        #        
        #        
                 
                 

Fig. 1
Fig. 2

Sample 2

sample2.txt

20 40 11 5 1 36
   #   #    #           ::::::::::::::::
       #    #            :::::::::.:::::
###### #### #             :::::::.::::::
        #   #             ::::::.::::   
            #             :::::::.::    
       ##   #              ::::::..     
  ######    #              ::::::..     
  #  # #    #                ::::...#   
     #                          ....    
     # #                        ... #   
  #  # ##          ###      #   .. ..   
  ####  #          ###         #. ..    
   #    #   #      ###           ..     
   #    ## ##                  #...     
   #    #   #                   ...     
   ######   #           ##     ...      
   #        #           ##     ...      
       #    #                 ...       
   #   #    #                ...        
   #   #    #               ...         

Fig. 3
Fig. 4

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

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

相关文章

Leetcode75- 种花问题

间隔种花 也就是 0 0 0 或者开头 0 0 结尾 0 0 也就是这三个地方可以种花 然后分别判断 最后根据提交结果分析漏掉的情况 比如 n为0 和 数组长度只有一个的情况 使用枚举可以很快解题

技术男的审美反击:UI配置化新纪元

之前常常被甲方的领导说&#xff0c;我们全是一群钢铁直男&#xff0c;一点不懂审美&#xff0c;其实我们心里边想的 “您说得对啊&#xff01;&#xff01;&#xff01;&#xff01;” 这个可能和理工科有关系吧&#xff0c;理工男好像都差不多&#xff0c;所以这次我们就把很…

Vue的学习(二)

目录 一、class及style的绑定 1.v-bind:class绑定类名 绑定class为对象 ​编辑2. v-bind:class绑定类名 绑定class为对象 3.v-bind:class绑定类名 绑定class为数组 1) v-bind:class绑定类名 绑定class为数组 方法一&#xff1a; 2) v-bind:class绑定类名 绑定class为数组…

实验4-2-1 求e的近似值

//实验4-2-1 求e的近似值 /* 自然常数 e 可以用级数 11/1!1/2!⋯1/n!⋯ 来近似计算。 本题要求对给定的非负整数 n&#xff0c;求该级数的前 n1 项和。 输入格式:输入第一行中给出非负整数 n&#xff08;≤1000&#xff09;。 输出格式:在一行中输出部分和的值&#xff0c;保留…

nginx: [error] open() “/run/nginx.pid“ failed (2: No such file or directory)

今天 准备访问下Nginx服务&#xff0c;但是 启动时出现如下报错&#xff1a;&#xff08;80端口被占用&#xff0c;没有找到nginx.pid文件&#xff09; 解决思路&#xff1a; 1、 查看下排查下nginx服务 #确认下nginx状态 ps -ef|grep nginx systemctl status nginx#查看端口…

数据结构——时间和空间复杂度

目录 一、时间复杂度和空间复杂度是什么 二、为什么要有时间复杂度和空间复杂度 三、时间复杂度 四、空间复杂度 一、时间复杂度和空间复杂度是什么 在生活中&#xff0c;我们做一件事情需要花费一定的时间和一定的空间&#xff0c;举一个例子&#xff1a; 一个工厂需要制…

从根儿上学习spring 十一 之run方法启动第四段(5)

图15-AbstractAutowireCapableBeanFactory#doCreateBean方法 我们接着讲doCreateBean方法&#xff0c;之前对循环依赖做了些解释&#xff0c;我们接着往下看populateBean(beanName, mbd, instanceWrapper)方法 图15-572行 这行就是调用populateBean(beanName, mbd, instanceW…

目标检测——YOLOv10: Real-Time End-to-End Object Detection

YOLOv10是在YOLOv8的基础上&#xff0c;借鉴了RT-DETR的一些创新点改进出来的 标题&#xff1a;YOLOv10: Real-Time End-to-End Object Detection论文&#xff1a;https://arxiv.org/pdf/2405.14458源码&#xff1a;https://github.com/THU-MIG/yolov10 1. 论文介绍 在过去的几…

【C语言】详解feof函数和ferror函数

文章目录 前言1. feof1.1 feof函数原型1.2 正确利用函数特性读写文件1.2.1 针对文本文件1.2.2 针对二进制文件 1.3 feof函数的原理1.4 feof函数实例演示 2. ferror2.1 ferror函数原型 前言 或许我们曾在网络上看过有关于feof函数&#xff0c;都说这个函数是检查文件是否已经读…

Windows系统使用内网穿透配置Mysql公网地址实现IDEA远程连接

文章目录 前言1. 本地连接测试2. Windows安装Cpolar3. 配置Mysql公网地址4. IDEA远程连接Mysql5. 固定连接公网地址6. 固定地址连接测试 前言 IDEA作为Java开发最主力的工具&#xff0c;在开发过程中需要经常用到数据库&#xff0c;如Mysql数据库&#xff0c;但是在IDEA中只能…

【Python学习手册(第四版)】学习笔记15-文档(注释、PyDoc等)

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文主要介绍程序的文档概念。包括为程序编写的注释&#xff0c;以及内置工具的文档。讲解文档字符串、Python的在线手册等资源、以及PyDoc的help函数和网页接口。…

蒙电通无人机航线规划系统 雷达点云电力应用软件

蒙电通无人机航线规划系统&#xff0c;它可进行标记杆塔、切档、自动对点云数据分类和点云抽稀等处理&#xff0c;按3张或6张照片自动生成航线&#xff0c;或按自定义航线模型生成航线&#xff0c;支持安全性检测。在满足当地巡检标准的前提下&#xff0c;系统操作非常简便。 …

llama神经网络的结构,llama-3-8b.layers=32 llama-3-70b.layers=80; 2000汉字举例说明

目录 llama-3-8b.layers=32 llama-3-70b.layers=80 llama神经网络的结构 Llama神经网络结构示例 示例中的输入输出大小 实际举例说明2000个汉字文本数据集 初始化词嵌入矩阵 1. 输入层 2. 嵌入层 3. 卷积层 4. 全连接层 llama-3-8b.layers=32 llama-3-70b.laye…

跑深度学习模型Ⅲ:正确安装与torch版本对应的其他torch包

pytorch的正确安装可以回看我前面的博客跑深度学习模型Ⅱ&#xff1a;一文安装正确pytorch及dgl-CSDN博客 这篇博客将安装torch_grometric&#xff0c;torch_scatter, torch_sparse, torch_cluster库 1. 查看自己的torch版本 进入cmd 切换到要用的python环境中&#xff0c;输…

ADB Installer 0 file(s)copied

在为泡面神器刷安卓&#xff0c;做准备工作装ADB时报错了&#xff0c;以下是报错提示 再用cmd命令adb version验证下&#xff0c;提示adb不是有效命令&#xff0c;百分百安装失败了&#xff0c;往上各种搜索查询均没有对症的&#xff0c;其中也尝试了安装更新版本的&#xff0c…

2024版本IDEA创建Servlet模板

IDEA 版本 2024.1.4 新版本的 IDEA 需要自己创建 Servlet 模板 旧版本 IDEA 看我这篇文章&#xff1a;解决IDEA的Web项目右键无法创建Servlet问题_2024idea无法创建servlet项目-CSDN博客文章浏览阅读216次&#xff0c;点赞7次&#xff0c;收藏3次。解决IDEA的Web项目右键无法创…

AGI思考探究的意义、价值与乐趣 Ⅴ

搞清楚模型对知识或模式的学习与迁移对于泛化意味什么&#xff0c;或者说两者间的本质&#xff1f;相信大家对泛化性作为大语言模型LLM的突出能力已经非常了解了 - 这也是当前LLM体现出令人惊叹的通用与涌现能力的基础前提&#xff0c;这里不再过多赘述&#xff0c;但仍希望大家…

【Python学习手册(第四版)】学习笔记14-迭代器和列表解析(一)

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文主要以通俗易懂的语言介绍迭代器&#xff08;文件迭代、手动迭代iter和next等&#xff09;&#xff0c;列表解析式包括基础知识包括写法、文件上使用列表解析…

繁简之争:为什么手机芯片都是 ARM

RISC 和 CISC 指令集 之前的文章《揭秘 CPU 是如何执行计算机指令的》中说到&#xff0c;如果从软件的角度来讲&#xff0c;CPU 就是一个执行各种计算机指令&#xff08;Instruction Code&#xff09;的逻辑机器。 计算机指令集是计算机指令的集合&#xff0c;包括各种类型的…

Redis进阶(四):哨兵

为了解决主节点故障&#xff0c;需要人工操作切换主从的情况&#xff1b;因此需要一种方法可以自动化的切换&#xff1a;哨兵的引入大大改变这种情况。 哨兵的基本概念 自动切换主从节点 哨兵架构 1、当一个哨兵节点发现主节点挂了的时候&#xff0c;还需要其他节点也去检测一…