Python 中的 8 拼图问题

17 Mar 2025 | 6 分钟阅读

本文介绍了 8 拼图问题的解决方案。提供一个3x3 的棋盘,上面有 8 个数字块(每个块的数字从 1 到 8)和一个单独的空格。目标是利用空白格将数字块排列成目标状态。可以将相邻的四个(左、右、上、下)数字块移动到空位

例如,

8 Puzzle problem in Python

1. DFS (深度优先搜索,穷举法)

我们可以在状态空间树(一个特定问题的状态集合,即从初始状态可以到达的所有状态)上执行深度优先搜索

8 Puzzle problem in Python

图:8 拼图的状态空间树

在此解决方案中,进一步的移动可能并不总是让我们更接近目标,反而会让我们远离。无论初始状态如何,状态空间树都会沿着根节点的左侧路径搜索。使用此方法,可能永远找不到目标节点

2. BFS (广度优先搜索,穷举法)

我们可以使用广度优先方法搜索状态空间树。它总是能找到最接近根的目标状态。但是,该算法无论初始状态如何,都会尝试与 DFS相同的移动序列

3. 分支限界法

通过避免搜索不包含目标节点的子树,一个“智能”的评估函数,也称为近似成本函数,可以经常加速查找目标节点的过程。然而,它不使用回溯法,而是执行类似 BFS 的搜索

基本上,分支限界法涉及三种不同类型的节点。

  1. 活节点是已生成但其子节点尚未生成的节点。
  2. E 节点(一个活节点)的后继节点正在被检查。换句话说,E 节点是当前正在扩展的节点。
  3. 死节点是指已生成但不再进一步开发或检查的节点。死节点已经扩展了其所有后继节点。

成本函数

在搜索树中,每个节点 Y 都有一个相应的成本。下一个E 节点可以通过成本函数找到。具有最低成本的 E 节点是下一个。该函数可以定义为:

8 拼图算法的最佳成本函数是:

我们假设将一块数字块向任何方向移动将花费一个单位。基于此,我们为 8 拼图算法创建以下成本函数:

有一个算法可以估计 h(y) 的未知值,该算法是可用的。

最终算法

  • 为了维护活节点列表,算法LCSearch 使用Least()Add() 函数。
  • Least() 识别一个具有最小 c(y) 的活节点,将其从列表中移除,然后返回。
  • Add(y)y 添加到活节点列表中。
  • Add(y) 将活节点列表实现为最小堆

上述算法从提供的 8 拼图起始配置到达最终配置所走的路径如下图所示。请注意,只有成本函数值最低的节点才会被扩展。

8 Puzzle problem in Python

代码

输出

1 2 3 
5 6 0 
7 8 4 

1 2 3 
5 0 6 
7 8 4 

1 2 3 
5 8 6 
7 0 4 

1 2 3 
5 8 6 
0 7 4