胡慧华
菜单
首页人工智能机器学习深度学习项目实践关于我
跳至课程正文
← 人工智能课程

ARTIFICIAL INTELLIGENCE · COURSE 03

搜索:怎样找到一条可行路线

理解状态、行动和搜索策略,比较路径代价与探索过程。

第 03 / 18 课20–30 分钟(含实验)无需密钥 · 本地实验
透明迷宫中的青色路径连接起点与终点,呈现搜索和路径规划
让机器寻找答案与行动
  • 状态空间
  • 路径搜索
01

START WITH A QUESTION

出口在地图上,怎样一步步走到那里?

你站在迷宫入口,知道哪些路口相连,却不知道该先走哪条路。每一次选择都会改变位置。可以不断尝试,但如果总是回到已经走过的路口,就会浪费时间。搜索把这种尝试组织成有顺序、可记录的过程。

本课使用六个地点构成的地图。广度优先先看近处的所有选择,深度优先先沿一条分支继续走。两者都不需要训练模型;差别在于先探索哪个候选状态。

02

BUILD YOUR VOCABULARY

先把三个概念讲清楚

CONCEPT 01

状态与行动

状态描述当前情况,行动规定可以怎样改变情况。地图中,状态可以是所在路口,行动可以是走到相邻路口。

放进场景看

从入口 S 可以走到 A 或 B,但不能直接跳到终点 G。

CONCEPT 02

待探索集合与已访问集合

前者记录未来还要检查的状态,后者防止反复探索相同状态。一个集合负责安排顺序,另一个负责避免循环。

放进场景看

访问过 A 后,遇到回到 A 的道路时不再重复加入。

CONCEPT 03

路径长度与代价

长度可以是行动次数,代价可以是时间或距离。广度优先在每一步代价相同时找到最少步数的路径;道路代价不同就不能直接等同于最便宜。

放进场景看

两段很长的道路,可能比三段短路更慢。

03

FOLLOW THE PROCESS

把原理放进完整流程

  1. 01

    加入起点

    将只含起点的路径放进待探索集合,记录已经见过的状态。

  2. 02

    取出候选

    广度优先从队首取出;深度优先从栈顶取出。

  3. 03

    展开邻居

    沿着合法道路加入尚未访问的状态,并保留到达它的路径。

  4. 04

    判断与停止

    找到目标就返回路径;候选耗尽则说明在当前地图中不可达。

按层展开,而不是凭感觉转弯
已探索深度可能到达已知事实
0 步S起点已知
1 步A、B先考察所有一步可达位置
2 步C、D新状态保存来路,重复状态跳过
3 步G等代价时已找到最少步数路径
04

CHANGE ONE THING & OBSERVE

逐步比较广度优先与深度优先

切换策略,点击下一步。观察图上当前节点、已访问节点、候选集合和最终路径;所有边的代价都是 1。

INTERACTIVE LAB / 03
六个地点的等代价地图,每条边代价为一SABCDG
当前节点S
候选集合A、B
已探索1 个

到达当前节点的路径:S。继续展开候选。

候选集合按内部队列或栈的存储顺序显示;深度优先从右端取出。本例在发现节点时去重。

05

KNOW THE LIMITS

哪些结论不能直接推出?

先找到不等于代价最低

深度优先可能先找到较长路线;广度优先的最少步保证也要求每步代价相同。

启发式不是凭空猜答案

启发式是估计剩余代价的线索。A* 等方法会利用它引导搜索,本课先掌握不使用估计的两种策略。

06

READ, RUN & EXPLAIN

用 Python 队列执行广度优先搜索

以下示例仅使用 Python 3 标准库,可复制到本地 Python 环境运行。先看每一行的作用,再修改一个输入观察结果;无需网络或密钥。

Python 3 · 完整示例下载 .py
from collections import deque
graph = {'S': ['A', 'B'], 'A': ['C'], 'B': ['D'], 'C': ['D'], 'D': ['G'], 'G': []}
queue = deque([['S']])
seen = {'S'}
while queue:
    path = queue.popleft()
    if path[-1] == 'G':
        print(path); break
    for node in graph[path[-1]]:
        if node not in seen:
            seen.add(node)
            queue.append(path + [node])

复制或下载只获取本课示例,不会自动执行。

逐行解释(12 行)
  1. 第 1 行from collections import deque

    导入双端队列,方便从开头取出较早加入的候选。

  2. 第 2 行graph = {'S': ['A', 'B'], 'A': ['C'], 'B': ['D'], 'C': ['D'], 'D': ['G'], 'G': []}

    字典记录各地点的相邻地点。与开场和互动使用同一张六地点地图。

  3. 第 3 行queue = deque([['S']])

    队列里的每一项是一条完整路径,最初只有起点。

  4. 第 4 行seen = {'S'}

    集合保存已经加入过的地点,避免循环与重复。

  5. 第 5 行while queue:

    只要还有候选,就继续搜索。

  6. 第 6 行 path = queue.popleft()

    取出最早加入的路径,因此先探索更短的路径。

  7. 第 7 行 if path[-1] == 'G':

    -1 表示列表最后一项;检查路径末尾是否为终点。

  8. 第 8 行 print(path); break

    找到目标就打印路径,并退出循环。分号分隔两个简短语句。

  9. 第 9 行 for node in graph[path[-1]]:

    枚举当前地点可以到达的相邻地点。

  10. 第 10 行 if node not in seen:

    只处理还没有加入过的地点。

  11. 第 11 行 seen.add(node)

    及时记录,避免其他分支重复加入。

  12. 第 12 行 queue.append(path + [node])

    创建延长后的新路径,放到队尾等待探索。

预期输出
['S', 'B', 'D', 'G']
07

CHECK YOUR UNDERSTANDING

换一个角度,检查自己是否理解

已回答 0 / 3 题 · 当前答对 0 题

1. 等代价地图中,广度优先保证什么?
2. 已访问集合主要解决什么问题?
3. 不同道路通行时间不同时,最少步数一定最快吗?
08

TAKE IT WITH YOU

带走三个判断,再做一次迁移练习

  • 搜索从状态、行动和目标构成的问题出发。
  • 广度与深度优先的核心差异是候选探索顺序。
  • 地图正确性、代价定义和访问记录共同影响结果。
参考与延伸阅读

本课例子、代码和模拟数据为教学设计。以下一手文档用于延伸核对,不代表对本示例的认证。