【AI】启发式搜索:贪婪最佳优先搜索与A*原理及python代码实现

  搜索算法是利用计算机的高性能来有目的的穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。

  搜索算法的形式化描述:状态、动作、状态转移、路径、测试目标
  状态:从原问题转化出的问题描述;
  动作:从当前时刻所处状态转移到下一时刻所处状态所进行操作,一般而言这些操作都是离散的;
  状态转移:对某一时刻对应状态进行某一种操作后,所能够到达状态;
  路径:一个状态序列,该状态序列被一系列操作所连接;
  测试目标:评估当前状态是否为所求解的目标状态;

一、问题引入:以寻找最短路径问题为例

问题:寻找从Arad到Bucharest的一条最短路径
在这里插入图片描述
辅助信息:任意一个城市与Bucharest的直线距离
在这里插入图片描述

二、启发式搜索(有信息搜索)

  在搜索的过程中利用与所求解问题相关的辅助信息,其代表算法为贪婪最佳优先搜索(Greedy best-first search)和A*搜索。
在这里插入图片描述

三、贪婪最佳优先搜索及Python实现

1.搜索原理与流程

  贪婪最佳优先搜索(Greedy best-first search):评价函数f (𝑛)=启发函数ℎ(𝑛)
  在最短路径问题中,启发函数为此刻城市节点到终点城市Bucharest的直线距离,每一次搜索,下一个节点选择与此刻城市连接的所有节点中,与Bucharest的直线距离最短的城市节点。其搜索流程如下:
在这里插入图片描述

2.Python实现

代码实现为:

import numpy as np

straight_line = {
    'Arad':366,
    'Bucharest':0,
    'Craiova':160,
    'Drobeta':242,
    'Eforie':161,
    'Fagaras':178,
    'Giurgiu':77,
    'Hirsova':151,
    'Iasi':226,
    'Lugoj':244,
    'Mehadia':241,
    'Neamt':234,
    'Oradea':380,
    'Pitesti':98,
    'Rimnicu Vilcea':193,
    'Sibiu':253,
    'Timisoara':329,
    'Urziceni':80,
    'Vaslui':199,
    'Zerind':374,
    }

start = 'Arad'
end = 'Bucharest'

path = []            # 存储最优路线
path.append(start)
distance = []        # 存储最优路线的路线长度

for i in range(20):
    path1 = []       # path1中存储该节点的连接城市
    distance1 = []   # distance1中存储该节点连接城市的距离
    for a in range(len(edges)):
        if edges[a][0] == path[-1]:
            path1.append(edges[a][1])  
            distance1.append(edges[a][-1])
    # 贪婪最优搜索
    min_distance = 1000
    for b in range(len(path1)):
        if straight_line[path1[b]] < min_distance:
            min_distance = straight_line[path1[b]]
            temp_distance = distance1[b]
            temp_path = path1[b]
            
    path.append(temp_path)
    distance.append(temp_distance)
    
    if temp_path == end:
        break
        
X = ' ——> '.join(path)
Y = np.sum(distance)
print('贪婪搜索_最优路线为:', X)
print('贪婪搜索_最优路线长度为:', Y)

运行结果为:

贪婪搜索_最优路线为: Arad ——> Sibiu ——> Fagaras ——> Bucharest
贪婪搜索_最优路线长度为: 450

3.贪婪最佳优先搜索不足之处

(1)贪婪最佳优先搜索不是最优的。经过Sibiu到Fagaras到Bucharest的路径比经过Rimnicu Vilcea到Pitesti到Bucharest的路径要长32公里。
(2)启发函数代价最小化这一目标会对错误的起点比较敏感。考虑从Iasi到Fagaras的问题,由启发式建议须先扩展Neamt,因为其离Fagaras最近,但是这是一条存在死循环路径。
(3)贪婪最佳优先搜索也是不完备的。所谓不完备即它可能沿着一条无限的路径走下去而不回来做其他的选择尝试,因此无法找到最佳路径这一答案。
(4)在最坏的情况下,贪婪最佳优先搜索的时间复杂度和空间复杂度都是O(𝑏^𝑚),其中𝑏是节点的分支因子数目、𝑚是搜索空间的最大深度。

四、A*搜索及Python实现

1.搜索原理与流程

  A*搜索:评价函数:f (𝑛) = g(𝑛) + ℎ(𝑛)
  g(𝑛) 表示从起始节点到节点𝑛的开销代价值;
  ℎ(𝑛) 表示从节点𝑛到目标节点路径中所估算的最小开销代价值;
  f(𝑛) 可视为经过节点𝑛 、具有最小开销代价值的路径;
在这里插入图片描述
  在最短路径问题中,g(𝑛)为当前选择的路径的实际距离,即从上一个节点到下一个节点的实际距离,ℎ(𝑛)为下一个节点到目标城市的直线距离。每一次搜索,下一个节点选择与此刻城市连接的所有节点中,g(𝑛)+ℎ(𝑛)最小的城市节点。其搜索流程如下:
在这里插入图片描述

2.Python实现

代码实现为:

import numpy as np

edges=[
    ('Arad','Zerind',75),
    ('Arad','Sibiu',140),
    ('Arad','Timisoara',118),
    ('Zerind','Oradea',71),
    ('Oradea','Sibiu',151),
    ('Timisoara','Lugoj',111),
    ('Lugoj','Mehadia',70),
    ('Mehadia','Drobeta',75),
    ('Drobeta','Craiova',120),
    ('Sibiu','Fagaras',99),
    ('Sibiu','Rimnicu Vilcea',80),
    ('Rimnicu Vilcea','Craiova',146),
    ('Fagaras','Bucharest',211),
    ('Rimnicu Vilcea','Pitesti',97),
    ('Pitesti','Bucharest',101),
    ('Bucharest','Giurgiu',90),
    ('Bucharest','Urziceni',85),
    ('Urziceni','Hirsova',98),
    ('Urziceni','Vaslui',142),
    ('Hirsova','Eforie',86),
    ('Vaslui','Iasi',92),
    ('Iasi','Neamt',87),
]

straight_line = {
    'Arad':366,
    'Bucharest':0,
    'Craiova':160,
    'Drobeta':242,
    'Eforie':161,
    'Fagaras':178,
    'Giurgiu':77,
    'Hirsova':151,
    'Iasi':226,
    'Lugoj':244,
    'Mehadia':241,
    'Neamt':234,
    'Oradea':380,
    'Pitesti':98,
    'Rimnicu Vilcea':193,
    'Sibiu':253,
    'Timisoara':329,
    'Urziceni':80,
    'Vaslui':199,
    'Zerind':374,
    }

start = 'Arad'
end = 'Bucharest'

path = []            # 存储最优路线
path.append(start)
distance = []        # 存储最优路线的路线长度

for i in range(20):
    path1 = []       # path1中存储该节点的连接城市
    distance1 = []   # distance1中存储该节点连接城市的距离
    for a in range(len(edges)):
        if edges[a][0] == path[-1]:
            path1.append(edges[a][1])  
            distance1.append(edges[a][-1])
    # A*搜索
    fxx = 1000
    for b in range(len(path1)):
        fxx_min = straight_line[path1[b]] + distance1[b]
        if fxx_min < fxx:
            fxx = fxx_min
            temp_distance = distance1[b]
            temp_path = path1[b]
            
    path.append(temp_path)
    distance.append(temp_distance)
    
    if temp_path == end:
        break
        
X = ' ——> '.join(path)
Y = np.sum(distance)
print('A*搜索_最优路线为:', X)
print('A*搜索_最优路线长度为:', Y)

运行结果为:

A*搜索_最优路线为: Arad ——> Sibiu ——> Rimnicu Vilcea ——> Pitesti ——> Bucharest
A*搜索_最优路线长度为: 418

3.A*搜索总结

在这里插入图片描述

参考资料

中国大学MOOC浙江大学:人工智能

实现Python中的贪婪最佳优先搜索迷宫,你可以遵循以下步骤: 1. 创建一个二维的迷宫矩阵,其中包含障碍物(墙壁)和可通行的路径。你可以使用一个列表或者数组来表示迷宫。 2. 定义起点和终点的坐标,并确保它们在可通行的路径上。 3. 创建一个字典或者优先队列来保存已访问的节点,并初始化起点。 4. 创建一个字典或者优先队列来保存每个节点的启发式值(即到达终点的预估距离)。这个启发式值可以使用欧几里得距离或者曼哈顿距离等算法来计算。 5. 创建一个空的路径列表来保存最终的路径。 6. 进入循环,直到终点被找到或者所有的节点都被访问: a. 从已访问的节点中选择一个未被探索的节点,该节点的启发式值最小。如果启发式值相同,则选择最先被访问的节点。 b. 如果选择的节点是终点,则停止循环,路径已找到。 c. 遍历选择的节点的所有邻居节点: - 如果邻居节点未被访问过,则将其添加到已访问的节点中,并计算它的启发式值。 - 如果邻居节点已经被访问过,比较当前路径是否比之前的路径更短,如果更短,则更新路径和启发式值。 7. 如果所有的节点都被访问过,但是终点未被找到,则表示没有可行的路径。 8. 按照从终点到起点的顺序,回溯路径列表,得到最终的路径。 这样,你就可以使用贪婪最佳优先搜索算法来解决迷宫问题了。希望这对你有所帮助!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值