8拼图AI游戏BFS算法实现出现无限循环问题如何解决
问题根因
- 第一,无解状态判断缺失:8拼图只有当初始状态和目标状态的逆序数奇偶性一致时才有解,如果你传入的初始状态本身无解,BFS会遍历完所有可达状态才退出,过程中看起来就是无限循环。
- 第二,状态查重效率极低:你用
list存储explored已访问集合和frontier队列,Python中列表的in操作是*O(n)*时间复杂度,8拼图总共有9! = 362880种合法状态,当状态量上来后,每次查重要遍历数万甚至数十万元素,运行速度会指数级变慢,看起来和无限循环没有区别。 - 第三,队列操作效率低:用普通列表的
pop(0)实现出队也是*O(n)*时间复杂度,队列越长操作越慢,进一步加剧性能问题。
修复方案
1. 新增逆序数校验逻辑
8拼图的可解性判断规则:去掉空位0,统计所有数字前面比它大的数字的总个数,初始和目标的逆序数奇偶性相同才有解,在BFS开始前加这个校验,无解直接返回避免无意义遍历。
2. 替换查重存储结构
把explored从列表改成集合,状态存成不可变的tuple类型(列表无法存入集合),集合的in操作是*O(1)*时间复杂度,可将查重效率提升上千倍。
3. 替换队列实现
用Python内置的collections.deque实现队列,popleft()操作是*O(1)*时间复杂度,大幅提升出队效率。
4. 优化状态生成逻辑避免分支写错
以下是修复后的可运行代码:
from collections import deque goalState = [0, 1, 2, 3, 4, 5, 6, 7, 8] # 计算逆序数奇偶性 用于判断可解性 def count_inversion(state): nums = [x for x in state if x != 0] count = 0 for i in range(len(nums)): for j in range(i): if nums[j] > nums[i]: count += 1 return count % 2 def switch(lst, index1, index2): newList = lst.copy() newList[index1], newList[index2] = newList[index2], newList[index1] return tuple(newList) def getNextStates(state): nextStates = [] state_list = list(state) emptyTile = state_list.index(0) # 上下左右四个方向的位置偏移量 dirs = [-3, 3, -1, 1] for d in dirs: new_pos = emptyTile + d if 0 <= new_pos < 9: # 避免左右移动跨行的非法情况 if d == -1 and emptyTile % 3 == 0: continue if d == 1 and emptyTile % 3 == 2: continue nextStates.append(switch(state_list, emptyTile, new_pos)) return nextStates def breadthFirst(initialState, goal): global exploredCount, visitedCount # 先校验是否有解 if count_inversion(initialState) != count_inversion(goal): print("当前初始状态无解") return None exploredCount = 1 visitedCount = 0 initial = tuple(initialState) goal_tuple = tuple(goal) frontier = deque([initial]) explored = set() print("开始遍历....") while frontier: state = frontier.popleft() if state == goal_tuple: print("找到目标状态") return list(state) explored.add(state) visitedCount += 1 nextStates = getNextStates(state) for next_state in nextStates: if next_state not in explored and next_state not in frontier: frontier.append(next_state) exploredCount += 1 return initialState
内容的提问来源于stack exchange,提问作者h0sny
相关产品推荐
相关产品推荐

