python import heapq def manhattan_distance(state, goal): """ 计算八数码问题的曼哈顿距离(启发函数h(n),可采纳) :param state: 元组,当前棋局状态 :param goal: 元组,目标棋局状态 :return: 整数,曼哈顿距离总和(估计代价) """ distance = 0 # 预存目标状态中每个数字的位置,提升计算效率 goal_pos = {num: (i//3, i%3) for i, num in enumerate(goal)} for i, num in enumerate(state): if num != 0:# 空格不计入距离,仅计算数字位置差 x1, y1 = i//3, i%3# 当前数字的行列坐标 x2, y2 = goal_pos[num]# 数字的目标行列坐标 distance += abs(x1 - x2) + abs(y1 - y2) return distance def get_neighbors(state): """ 生成当前棋局的所有合法子状态(空格四向移动,对应操作集合O) :param state: 元组,当前棋局 :return: 列表,合法子状态集合 """ neighbors = [] empty_idx = state.index(0)# 定位空格位置索引 x, y = empty_idx//3, empty_idx%3# 空格的行列坐标 directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]# 空格四向移动 for dx, dy in directions: new_x = x + dx new_y = y + dy # 验证移动合法性:空格需在3×3网格内 if 0 <= new_x < 3 and 0 <= new_y < 3: new_empty_idx = new_x * 3 + new_y# 新空格位置索引 # 交换空格与相邻数字,生成子状态 state_list = list(state) state_list[empty_idx], state_list[new_empty_idx] = state_list[new_empty_idx], state_list[empty_idx] neighbors.append(tuple(state_list)) return neighbors def a_star_8puzzle(start, goal): """ A*算法求解八数码问题,结合实际代价g(n)和启发代价h(n) :param start: 元组,初始棋局(初始状态S) :param goal: 元组,目标棋局(目标状态G) :return: 列表,从初始到目标的最优路径(无路径返回空列表) """ # 开放列表:用小根堆存储 (f(n), g(n), 当前状态, 路径),优先扩展f(n)最小的状态 open_list = [] heapq.heappush(open_list, (0, 0, start, [start])) # 关闭列表:存储已扩展的状态,避免重复计算 close_list = set() # g_dict:记录每个状态到初始状态的实际代价,优化重复状态的g值更新 g_dict = {start: 0} while open_list: # 取出f(n)最小的状态,作为当前扩展节点 f_n, g_n, current_state, path = heapq.heappop(open_list) # 目标检测:到达目标状态则返回最优路径 if current_state == goal: return path # 若当前状态已扩展,直接跳过,避免重复处理 if current_state in close_list: continue close_list.add(current_state) # 扩展当前状态的所有子状态,计算f(n)并加入开放列表 for neighbor in get_neighbors(current_state): new_g = g_n + 1# 移动一步,实际代价g(n)加1 # 若子状态未访问,或新路径的g值更小(更新更优路径) if neighbor not in g_dict or new_g < g_dict[neighbor]: g_dict[neighbor] = new_g h_n = manhattan_distance(neighbor, goal)# 计算启发代价 new_f = new_g + h_n# 评估函数f(n) = g(n) + h(n) new_path = path.copy() new_path.append(neighbor) heapq.heappush(open_list, (new_f, new_g, neighbor, new_path)) return [] # ------------------- 测试代码 ------------------- if __name__ == "__main__": # 初始状态(可替换为任意合法八数码棋局) start_state = (2, 8, 3, 1, 6, 4, 7, 0, 5) goal_state = (1, 2, 3, 4, 5, 6, 7, 8, 0)# 目标状态 a_star_path = a_star_8puzzle(start_state, goal_state) if a_star_path: print("A*算法找到八数码最优路径,共{}步:".format(len(a_star_path)-1)) for i, state in enumerate(a_star_path): print(f"第{i}步:") # 格式化输出棋局,便于观察状态变化 for row in range(3): print(state[row*3 : (row+1)*3]) print("-" * 10) else: print("该八数码棋局无解(八数码有1/2概率无解,需确保初始状态合法)") |