图论经典A-Star(A*) Algorithm最短路径,networkx,Python(1)

news2024/11/17 0:28:12

图论经典A-Star(A*) Algorithm最短路径,networkx,Python(1)

A-Star Algorithm,即为A*(A星)算法,图的最短路径。

(1)A-Star(A*)算法需要事先知道起点和终点才能求出最优路径。A-Star算法大量运用在游戏编程中的人物角色选路AI程序中。现代游戏编程,涉及到路径选择和规划的,大部分基于A*算法实现。然而,如果算法启动前不知道终点(起点已知),那么无法使用A-Star算法。

(2)A*算法核心是启发函数 F = G+H,启发函数驱动A*算法。假设当前节点是V,G是节点V到出发点的距离,H是节点V到终点的距离。A*算法应用在空间平面的距离计算,通常由两种:欧几里德解析几何距离,曼哈顿距离。用的较多的是曼哈顿距离。

(3)A*算法工作过程:出发点start和终点goal已经知道,假设现在选定了某个节点V,对于某个节点V,V到出发点start的曼哈顿距离算出为G,V到终点goal的曼哈顿距离为H,则节点V的启发函数值F=G+H。

A*需要维护两个列表:open_list和close_list,当选定节点V后,把所有与V邻接的节点放入open_list中,把这些新加入的点的父记为V,然后把节点V放入到close_list。此时查找open_list中所有节点的具有最小F值的节点 V' (此处是 V' 撇,不是 V,表示V选好后,进行第二轮选点的那个节点),V' 选出来后,再次把 V' 所有相邻的节点加入到open_list中,同时把 V' 从open_list中删掉,并把V' 加入到close_list中去。

在查找 V' 的邻接节点步骤中,如果邻接的节点已经在close_list中,则忽略,同时,如果 V' 的某一个邻接点N已经在open_list中,则比较当前节点 V' 到N的距离

(4)最终路径的产生:从终点开始。逆向的从终点开始,找出终点保存的父节点指向谁,然后逆向,然后再找到终点的父节点的父节点......,一路逆行查找,直到查找到父节点为出发点为止,即为A*选出来的路径。

 

现在,我用python简单写了一个A-Star算法的实现,networkx主要用来绘制图和装配与节点相关的内容:

import random
import time

import networkx as nx
import matplotlib.pyplot as plt

G_DIS = 'g_dis'
H_DIS = 'h-dis'
F = 'F'
WALKABLE = 'walkable'
PARENT = 'parent'



def my_graph():
    M = 7
    N = 9
    G = nx.grid_2d_graph(m=M, n=N)
    pos = nx.spring_layout(G, iterations=100)

    nx.draw_networkx(G, pos=pos,
                     # labels=labels, #labels = dict(((i, j), 'Phil') for i, j in G.nodes())
                     font_size=8,
                     font_color='white',
                     node_color='green',
                     node_size=500,
                     width=1)

    START = (2, 1)
    GOAL = (M - 1 - 1, N - 1 - 1)

    obstacle = 20  # 障碍物(断点、不可达点)数量
    road_closed_nodes = dummy_nodes(G)  # obstacle_nodes(G, START, GOAL, obstacle, M, N)

    nx.draw_networkx_nodes(
        G, pos,
        nodelist=road_closed_nodes,
        node_size=500,
        node_color="red",
        node_shape="x",
        # alpha=0.3,
        label='x'
    )

    print('G.nodes(data=True)', G.nodes(data=True))
    print('G.edges(data=True)', G.edges(data=True))

    path = a_star(G, START, GOAL)
    print('路线', path)

    nx.draw_networkx_nodes(
        G, pos,
        nodelist=path,
        node_size=400,
        node_color="red",
        node_shape='o',
        # alpha=0.3,
        # label='NO'
    )

    # 逆向的从父节点找出A*选的路。
    path_edges = []
    for i in range(len(path)):
        if (i + 1) == len(path):
            break
        path_edges.append((path[i], path[i + 1]))

    print('path_edges', path_edges)

    # 把path着色加粗重新描边
    nx.draw_networkx_edges(G, pos,
                           edgelist=path_edges,
                           width=8,
                           alpha=0.5,
                           edge_color="r")

    plt.axis('off')
    plt.show()


# 障碍物点
def obstacle_nodes(G, START, GOAL, obstacle, M, N):
    road_closed_nodes = []
    for i in range(obstacle):
        time.sleep(0.01)
        n = (random.randint(0, M - 1), random.randint(0, N - 1))
        if n == START or n == GOAL:
            continue
        if n in road_closed_nodes:
            continue

        G.nodes[n][WALKABLE] = False
        road_closed_nodes.append(n)

    return road_closed_nodes


def dummy_nodes(G):
    fun_nodes = []
    n1 = (1, 3)
    G.nodes[n1][WALKABLE] = False
    fun_nodes.append(n1)
    n2 = (1, 4)
    G.nodes[n2][WALKABLE] = False
    fun_nodes.append(n2)
    n3 = (1, 5)
    G.nodes[n3][WALKABLE] = False
    fun_nodes.append(n3)
    n4 = (1, 6)
    G.nodes[n4][WALKABLE] = False
    fun_nodes.append(n4)
    n5 = (2, 6)
    G.nodes[n5][WALKABLE] = False
    fun_nodes.append(n5)
    n6 = (3, 6)
    G.nodes[n6][WALKABLE] = False
    fun_nodes.append(n6)
    n7 = (4, 6)
    G.nodes[n7][WALKABLE] = False
    fun_nodes.append(n7)
    n8 = (5, 6)
    G.nodes[n8][WALKABLE] = False
    fun_nodes.append(n8)
    n9 = (5, 5)
    G.nodes[n9][WALKABLE] = False
    fun_nodes.append(n9)
    n10 = (5, 4)
    G.nodes[n10][WALKABLE] = False
    fun_nodes.append(n10)
    n11 = (5, 3)
    G.nodes[n11][WALKABLE] = False
    fun_nodes.append(n11)

    return fun_nodes


# A*寻路
def a_star(G, START, GOAL):
    open_list = []
    close_list = []

    vertex = START
    loop_flag = True
    while loop_flag:
        print('-----')

        if vertex == GOAL:
            print('到达', vertex)
            close_list.append(vertex)
            # loop_flag = False
            break

        print('选中', vertex)
        close_list.append(vertex)
        for node in nx.neighbors(G, vertex):
            # 如果n在close_list或者不可行,忽略
            try:
                walkable = G.nodes[node][WALKABLE]
            except:
                walkable = True

            print('walkable', walkable)
            if (not walkable) or (node in close_list):
                continue

            print('遍历', node)

            if node in open_list:
                print(node, '在open_list')

                node_g_dis = G.nodes[node][G_DIS]
                vertex_g_dis = G.nodes[vertex][G_DIS]
                sum_g_dis = manhattan(vertex, node) + vertex_g_dis
                # 更新权值
                if sum_g_dis < node_g_dis:
                    G.nodes[node][PARENT] = vertex
                    G.nodes[node][G_DIS] = sum_g_dis
                    G.nodes[node][F] = sum_g_dis + manhattan(GOAL, node)
            else:
                G.nodes[node][G_DIS] = manhattan(node, START)
                h_dis = manhattan(node, GOAL)
                G.nodes[node][H_DIS] = h_dis

                sum_f_dis = G.nodes[node][G_DIS] + h_dis
                G.nodes[node][F] = sum_f_dis

                G.nodes[node][PARENT] = vertex
                open_list.append(node)

            # print('G.nodes(data=True)', G.nodes(data=True))
            print('open_list', open_list)

            f_list = []
            for n in open_list:
                f_list.insert(0, (n, G.nodes[n]))
            print('f_list', f_list)

            min_f = min(f_list, key=lambda x: x[1][F])
            print('min_f', min_f)
            point = min_f[0]

        print('F最小点', point)
        open_list.remove(min_f[0])
        print('close_list', close_list)
        print('open_list', open_list)
        vertex = point

    t = GOAL
    path = [t]
    is_find = False
    while not is_find:
        for n in G.nodes(data=True):
            if n[0] == t:
                parent = n[1][PARENT]
                path.append(parent)

                if parent == START:
                    is_find = True
                    break
                t = parent

    list.reverse(path)
    return path


# 计算曼哈顿距离
def manhattan(u, v):
    dis = abs(u[0] - v[0]) + abs(u[1] - v[1])
    return dis


if __name__ == '__main__':
    my_graph()

 

运行代码,跑几轮,看看程序选的路线如何。出发点是START,目的地是GOAL。图中标记红色叉(X)的节点是故意随机生成的断点、障碍物、陷阱,特意用来挑战A-Star算法智商 :-),图中红‘X’表明这个节点不可通行,不能用于选路。障碍物点数量越多,选路难度越大,本例是20个(obstacle = 20)障碍物点。注意本例的随机障碍物点生成规则,程序生成的随机障碍物点如果刚好是起点或终点,则忽略;如果生成的随机障碍物点刚好已经在之前生成过,则同意忽略。这意味着,可能每次生成的随机障碍物点zong's不等于20,而是<=20。

最终的红色圆点即为出发点到终点的路线节点,把节点用淡红色粗线连起来,即为A*算法选出来的路线。

在本例出发点是(1,1),终点是(5,7)。出发点和终点和程序代码开始的M,N值相关。

下面是运行了几轮程序,A*选择的路线( 起点(1,1) -> 终点(5,7) ,红色点连成的淡红色(red,alpha=0.5)粗线为形成的路线)截图:

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16 

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

 

程序当前存在一些问题,对障碍物点没做特殊处理,只是不让障碍物刚好是起点和终点。如果随机生成的障碍物点把出发点和终点隔绝死,或者中间某处路隔绝断,程序就就选不到路运行错误。后续还需要对这个程序改进和优化。

下面来些有趣的内容:给A-Star算法挖坑,看它会不会跳进去 :-)

现在,针对A*算法的特点,我造一堵特殊的墙,一个凹形的墙。看看A星算法是否会跳进这堵墙形成的坑。实验的做法是修改起点和终点,把起点修改为(3,1),终点修改为(3,7)。同时,不再随机生成障碍点,而是在(3,1)和(3,7)之间特意挑选一些位置、写死一批(9个点)不可通行的节点(仍然用X标记),这批不可通行的节点形成一个连续的凹形阻挡面,正面对(3,1)节点,程序运行几轮的截图:

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

 

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAemhhbmdwaGls,size_20,color_FFFFFF,t_70,g_se,x_16

 A-Star聪明的绕过了这个大坑(凹形墙),顺利达到(3,7)点。

 

 

 

(未完待续...)

 

 

图论BFS(Breath First Search)Algorithm广度优先搜索遍历空间平面网格图路径选择,networkx,Python_zhangphil的博客-CSDN博客import randomimport networkx as nximport matplotlib.pyplot as pltWALKABLE = 'walkable'PARENT = 'parent'VISITED = 'visited'def my_graph(): M = 7 N = 9 G = nx.grid_2d_graph(m=M, n=N) pos = nx.spring_layout(G, iterations=100) ...https://blog.csdn.net/zhangphil/article/details/121267357

 

图论DFS(Depth First Search)Algorithm深度优先搜索遍历空间平面图选择路径,networkx,Python_图论 dfs_zhangphil的博客-CSDN博客import randomimport networkx as nximport matplotlib.pyplot as pltWALKABLE = 'walkable'PARENT = 'parent'VISITED = 'visited'def my_graph(): M = 7 N = 9 G = nx.grid_2d_graph(m=M, n=N) pos = nx.spring_layout(G, iterations=100) ...https://blog.csdn.net/zhangphil/article/details/121269870

https://zhangphil.blog.csdn.net/article/details/121171499https://zhangphil.blog.csdn.net/article/details/121171499

https://zhangphil.blog.csdn.net/article/details/121208538https://zhangphil.blog.csdn.net/article/details/121208538

 

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

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

相关文章

PhpStorm 2022.3.2消除顶部Windows窗口白色区域

问题图片&#xff1a; 解决方法&#xff1a;勾选Merge main menu with window title 效果图&#xff1a;

第三章:JavaScript 脚本语言(一)

一、简介 JavaScript是web页面中的一种脚本语言&#xff0c;由客户端浏览器解释执行。不需要编译&#xff0c;主要作用是将静态页面转换成用户交互的动态页面。 JavaScript主要有三大部分&#xff1a;ECMAScript (核心)&#xff0c;DOM&#xff08;文档对象模型&#xff09;&…

溯源取证-Linux内存取证 中难度篇

原谅我这么晚才出来文章&#xff0c;因为最近忙着录课&#xff0c;至于为啥没有基础篇&#xff0c;是因为靶场里没看见&#xff0c;哈哈 这个也是研究了好几个晚上才出来的东西&#xff0c;此处场景为linux环境下的rootkit病毒&#xff0c;我们通过这篇文章可以通过内存取证发…

Jmeter测试dubbo服务

1、什么是dubbo接口 Dubbo 接口是阿里巴巴开源的致力于提供高性能和透明化的RPC远程服务调用方案&#xff0c;以及SOA服务治理方案&#xff0c;dubbo框架告别了传统的web service的服务模式&#xff0c;进而改用provider和consumer模式进行服务。为什么是高性能的呢&#xff1f…

制作四个文件启动的镜像

一 环境搭建&#xff1a;vivado2018.3&#xff0c;petalinux2018.3&#xff0c; 1.petalinux环境设置 所使用的编译环境需要使用petalinux这个软件&#xff0c;《第五章Petalinux 的安装》里面的5.1-5.4。有详细的安装过程&#xff0c;按照第五章的顺序把环境搭建好。可以不装…

【PR 基础】新建序列

目录 一、新建序列 二、序列预设 三、设置 一、新建序列 在如下区域点击鼠标右键&#xff0c;选择 新建项目-》序列 或 点击工具栏中的文件-》新建-》序列 二、序列预设 &#xff08;1&#xff09;时基&#xff1a;就是指帧速率&#xff0c;也就是每秒播放帧的数量&#xf…

iOS Matter 操作证书签发方案

在 Matter 配网和操作中&#xff0c;为了信息交互的安全&#xff0c;在配网时&#xff0c;Commissioner自身需要完整的证书&#xff0c;同时需要向设备安装操作证书。 Matter 证书包含&#xff1a; RCA: 根证书 ICA: 中间证书&#xff0c;可选 NOC: 操作证书(注意有以下两种…

人工智能的前沿信息获取之使用文献数据库

人工智能的知识更新迭代非常迅速&#xff0c;因此对人工智能前沿的跟踪非常必要。本文主要介绍了使用文献数据库获取人工智能前沿信息的方法。 文献数据库是检索和下载论文的主要工具&#xff0c;对文献进行检索和下载的技巧在本科公共基础课《文献检索》或《信息检索》等类似…

家庭智能触摸面板开关一Homekit智能

触摸开关&#xff0c;即通过触摸方式控制的墙壁开关&#xff0c;其感官场景如同我们的触屏手机&#xff0c;只需手指轻轻一点即可达到控制电器的目的&#xff0c;随着人们生活品质的提高&#xff0c;触摸开关将逐渐将换代传统机械按键开关。 触摸开关控制原理 触摸开关我们把…

【ESP-IDF】介绍NVS

ESP-IDF是一款由乐鑫科技&#xff08;Espressif Systems&#xff09;开发的面向ESP32和ESP32-S系列芯片的开发框架&#xff0c;NVS&#xff08;Non-Volatile Storage&#xff09;是其中的一项功能。 NVS是一种用于在嵌入式系统中保存持久化数据的键值存储库。在ESP-IDF中&#…

虚拟化技术 — SR-IOV 单根 I/O 虚拟化

目录 文章目录 目录SR-IOVSR-IOV VEBSR-IOV VEPASR-IOV Multi-ChannelSR-IOV OvSSR-IOV 的应用使能 SR-IOV VFs挂在 VF 到 KVM 虚拟机中SR-IOV 的 NUMA 亲和性VF 的网络配置VFs Bonding SR-IOV 虚拟机的热迁移问题 SR-IOV 传统的 I/O 虚拟化方案需要 VMM 来捕获和模拟 VM 的 I…

400左右蓝牙耳机什么牌子音质好?400左右的无线蓝牙耳机推荐

过去几年苹果的AirPods深受大家欢迎&#xff0c;但要论最佳耳机&#xff0c;还要考虑佩戴类型&#xff0c;功能上又分降噪水平&#xff0c;甚至价格上也要实惠&#xff0c;毕竟对于不想太高预算来获得出色音质和舒适度的人来说&#xff0c;这也是他们心中的"最佳"产品…

Kubernetes那点事儿——调度策略

Kubernetes那点事儿——调度策略 前言一、静态Pod二、nodeSelector 节点选择器三、nodeName四、taint污点五、tolerations污点容忍六、容器资源限制七、nodeAffinity节点亲和性 前言 Kubernetes的强大之处离不开它的调度系统&#xff0c;它为Pod调度到某个Node上提供了多种方式…

Linux学习_设备树实现中断

Linux学习_设备树实现中断 中断层级结构设备树_中断控制器设备树_中断子节点驱动程序获取GPIO获取中断号申请中断中断处理函数 中断层级结构 就硬件而言&#xff0c;中断控制器指的就是GIC&#xff0c;但是实际在软件上&#xff0c;图中的GPIO等我们也称之为中断控制器。 外部…

[PyTorch]预训练权重的转换

众所周知&#xff0c;使用大量数据预训练后的骨干网络可以提升整个模型的泛化能力&#xff0c;而我们如果将网络的骨干网络替换后则不能直接使用原来的权重。这个项目的作用是在你替换骨干网络后可以将网络预训练权重一并“偷”过来。 下给结论&#xff1a;将DeeplabV3的骨干网…

详解 TCP(三次握手 + 四次挥手 + 滑动窗口 + 拥塞控制 + 和 UDP 做对比)

文章目录 1. TCP / IP五层模型和OSI七层模型1&#xff09;OSI七层模型2&#xff09;TCP/IP 五层模型 2. TCP和UDP1&#xff09; TCP首部结构2&#xff09;UDP首部结构3&#xff09;TCP和UDP的区别2.2 UDP和TCP对应的应用场景 3. TCP 建立连接时的三次握手1&#xff09;为什么需…

虚拟专用网VPN与网络地址转换NAT技术

1、专用网络或本地互联网 一方面现在随着个人电脑的增大&#xff0c;IP地址十分紧缺&#xff0c;所以如果为每一台电脑都分配个一个全球IP地址&#xff08;唯一的&#xff09;不太现实&#xff1b;另外一方面&#xff0c;很多机构&#xff08;比如大公司&#xff09;往往只需要…

阿里正式加入ChatGPT战局,“通义千问”上线后表现如何?

ChatGPT发布后&#xff0c;数月间全世界都对AI的能力有了新的认知。 ChatGPT掀起的战局&#xff0c;现在又多了一位选手了&#xff01; 阿里版类ChatGPT突然官宣正式对外开放企业邀测&#xff0c;由达摩院开发&#xff0c;名为“通义千问” 顾名思义&#xff0c;阿里正式加入Ch…

java实现钉钉自定义机器人发送消息

钉钉作为现在很多企业的移动办公平台&#xff0c;具有很多很强大的功能&#xff0c;可以帮助我们更加及时的发现问题&#xff0c;解决问题&#xff0c;今天我们做一个java实现钉钉自定义机器发送消息的功能。 首先&#xff0c;先放出官方文档地址&#xff1a;https://open.ding…

GIS在城市规划中的作用与应用

山海鲸可视化-GIS影像 简介 GIS&#xff08;地理信息系统&#xff09;是一种用于捕获、存储、管理、分析和显示地理空间数据的技术和工具。GIS可以用于各种领域&#xff0c;包括城市规划、土地管理、自然资源管理、公共安全、环境保护、气象预报、交通运输、农业、地质勘探、…