Posted on :: Updated on :: Tags:

「这个是江瑞老师 2024 秋季学期人工智能原理课程编程作业, 这里给出一种简单的理解. 同学们理性参考. 」

我不知道你是怎么看到这篇文章的, 但是我觉得使用搜索引擎应该搜不出这篇文章吧. 应该吧.

题目描述

本题的背景是连连看小游戏. $6 \times 6$ 的网格中分布着若干对字母 (可能重复), 玩家需要用线条连接每对相同的字母 (题目中没说线条之间能否相互交叉, 但我觉得应该不能), 线条可以超出 $6 \times 6$ 的网格区域. 下面是一个示例.

   │ C │ D │_A_│   │   │
───┼───┼───┼───┼───┼───┼
   │ B │   │   │ E │   │
───┼───┼───┼───┼───┼───┼
   │   │   │ C │ B │   │
───┼───┼───┼───┼───┼───┼
   │ C │ B │ E │   │   │
───┼───┼───┼───┼───┼───┼
   │ B │   │ D │   │   │
───┼───┼───┼───┼───┼───┼
_A_│   │   │   │   │ C │
───┼───┼───┼───┼───┼───┼

问题:

  1. 对任意一对字母, 找出它们之间的最短路径.
  2. 对任意一对字母, 找出它们之间转弯次数最少的路径.
  3. (选做) 用最少的转弯次数连接配对所有的字母对.

以上图中的一对字母 A (那个不是颜文字) 为例, 它们之间的最短路径为:

   │ C │ D │_A_│   │   │
───┼───┼───┼───┼───┼───┼
   │ B │ * │ * │ E │   │
───┼───┼───┼───┼───┼───┼
 * │ * │ * │ C │ B │   │
───┼───┼───┼───┼───┼───┼
 * │ C │ B │ E │   │   │
───┼───┼───┼───┼───┼───┼
 * │ B │   │ D │   │   │
───┼───┼───┼───┼───┼───┼
_A_│   │   │   │   │ C │
───┼───┼───┼───┼───┼───┼

它们之间的转弯次数最少的路径为:

 * │ * │ * │ * │   │   │
───┼───┼───┼───┼───┼───┼
 * │ C │ D │_A_│   │   │
───┼───┼───┼───┼───┼───┼
 * │ B │   │   │ E │   │
───┼───┼───┼───┼───┼───┼
 * │   │   │ C │ B │   │
───┼───┼───┼───┼───┼───┼
 * │ C │ B │ E │   │   │
───┼───┼───┼───┼───┼───┼
 * │ B │   │ D │   │   │
───┼───┼───┼───┼───┼───┼
_A_│   │   │   │   │ C │
───┼───┼───┼───┼───┼───┼

注意此处路径超出了网格区域, 这是允许的.

解题思路

第 1 问显然可以直接用广度优先搜索解决. (这节课为止还没有讲到 A* 之类的算法, 就不考虑了.) 第 2 问乍一看不太明晰, 但其实也可以用广度优先搜索. 第 3 问我还没想明白.

第 1 问

搞清楚下面几个要素就能够应用广度优先搜索了.

  • 状态(顶点): 当前格的坐标 $(x, y)$.
  • 初始状态: 起始格的坐标, 在上面的例子中为 $(3, 0)$ (以 $6 \times 6$ 网格的左上角为 $(0, 0)$).
  • 行动(边): 从 $(x, y)$ 格出发可以移动到 $(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)$ 中没有字母的格子.
  • 终止状态: 终点格的坐标.

第 2 问

在第 1 问中, 我们把「一步」(一个行动或一条边)老老实实地定义成从某格上下左右移动一格. 这样就能确保在进行广度优先搜索的时候, 搜索出的路径长度是最短的. 现在, 既然我们要使转弯的次数最少, 那么「一步」就应该定义成一次转弯.

  • 状态(顶点): $((x, y), d)$. 其中 $(x, y)$ 是当前格的坐标; $d$ 是上一次移动的方向, 取值为 $(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)$ 其中之一, 前四个各代表左, 右, 上, 下, 最后一个只在初始状态下出现, 原因稍后解释.
  • 初始状态: $((x_0, y_0), (0, 0))$, 其中 $(x_0, y_0)$ 是起始格的坐标.
  • 行动(边): 从状态 $((x, y), d)$ 出发, 可以到达状态 $((x, y) + n \cdot d^\prime, d^\prime)$. 其中 $n$ 为任意正整数, 代表了移动的距离; $d^\prime$ 为上下左右四个方向中任意与 $d$ 不同的方向. 两者满足: 格子 $(x, y) + n \cdot d^\prime$ 与 $(x, y)$ 之间的空间没有字母的阻隔.

提示

限制 $d^\prime$ 与 $d$ 不同是为了让每一次行动都是转向 (即不能选择和上一次行动一样的方向). 因为从初始状态出发可以选择上下左右任意一个方向, 所以将初始状态的 $d$ 特别设为 $(0, 0)$ 以与上下左右四个方向都不同 (你也可以设成 $(114, 514)$ 等任意富有个性的值).

  • 终止状态: 终止状态的坐标就是终点格的坐标, 方向任取, 只要搜索到终点格即停止搜索即可.

简单来说, 就是将路径中的每一条线段看成一次行动即可. 另外还需注意, 每次行动中, 需要将线段上的所有格子都加入闭节点表. 这样一来即可应用广度优先搜索. 代码就不粘在这儿了, 写得有点乱.

第 3 问

你行你上, 我是真不会.