猴子摘香蕉编程题是一个经典的人工智能规划问题,通常用于演示状态空间搜索或逻辑推理。其标准描述是:房间内有一只猴子、一个可移动的凳子和一串挂在天花板上的香蕉,猴子需要通过一系列动作(如移动、推凳子、爬凳子、摘香蕉)最终摘到香蕉。解题核心在于建立状态表示、定义动作、选择合适的搜索算法。

一、状态表示
一个完整的状态应包含以下信息:猴子位置、凳子位置、香蕉位置、猴子是否在凳子上(布尔值)、香蕉是否已被摘到(布尔值)。例如,可用三元组或类对象表示。位置通常用离散坐标(如0,1,2...)或字符串(如"A","B","C")表示。
二、动作定义
常见动作包括:
1. 移动(goto):猴子从当前位置走到另一位置,前提是猴子未在凳子上。
2. 推凳子(push):猴子与凳子在同一位置,可将其推到另一位置,前提是猴子未在凳子上。
3. 爬凳子(climb):猴子与凳子在同一位置,且猴子未在凳子上,则爬上去。
4. 爬下凳子(descend):猴子在凳子上,则爬下来。
5. 摘香蕉(grasp):猴子在凳子上且凳子与香蕉在同一位置,则摘到香蕉。
三、搜索算法选择
最常用宽度优先搜索(BFS)或深度优先搜索(DFS),因为状态空间有限且动作可逆。对于更复杂场景可使用A*搜索或迭代加深。由于问题简单,BFS能保证找到最短动作序列。
四、Python代码实现示例(BFS)
from collections import deque
# 定义状态类
class State:
def __init__(self, monkey, stool, banana, on_stool, has_banana):
self.monkey = monkey # 猴子位置
self.stool = stool # 凳子位置
self.banana = banana # 香蕉位置
self.on_stool = on_stool # 是否在凳子上
self.has_banana = has_banana
def __eq__(self, other):
return (self.monkey == other.monkey and
self.stool == other.stool and
self.banana == other.banana and
self.on_stool == other.on_stool and
self.has_banana == other.has_banana)
def __hash__(self):
return hash((self.monkey, self.stool, self.banana, self.on_stool, self.has_banana))
def __str__(self):
return f"猴:{self.monkey} 凳:{self.stool} 蕉:{self.banana} 上凳:{self.on_stool} 得蕉:{self.has_banana}"
# 动作生成函数
def get_successors(state):
successors = []
x, y, z = state.monkey, state.stool, state.banana
on, has = state.on_stool, state.has_banana
if has: # 已经摘到香蕉,无需动作
return []
# 1. 移动(猴子不在凳子上时可以走到其他位置)
if not on:
for new_pos in range(3): # 假设位置只有0,1,2
if new_pos != x:
successors.append(State(new_pos, y, z, on, has))
# 2. 推凳子(猴子与凳子同位置且不在凳子上)
if not on and x == y:
for new_pos in range(3):
if new_pos != y:
successors.append(State(new_pos, new_pos, z, on, has))
# 3. 爬凳子(猴子与凳子同位置且不在凳子上)
if not on and x == y:
successors.append(State(x, y, z, True, has))
# 4. 爬下凳子(猴子在凳子上)
if on:
successors.append(State(x, y, z, False, has))
# 5. 摘香蕉(猴子在凳子上且凳子与香蕉同位置)
if on and y == z:
successors.append(State(x, y, z, on, True))
return successors
# BFS搜索
def bfs(initial_state, goal_condition):
queue = deque([(initial_state, [])])
visited = set()
visited.add(initial_state)
while queue:
state, path = queue.popleft()
if goal_condition(state):
return path + [state]
for next_state in get_successors(state):
if next_state not in visited:
visited.add(next_state)
queue.append((next_state, path + [state]))
return None
# 目标条件:摘到香蕉
def goal_condition(state):
return state.has_banana
# 测试:初始状态:猴子在0,凳子在1,香蕉在2,未上凳,未得蕉
initial = State(0, 1, 2, False, False)
solution = bfs(initial, goal_condition)
if solution:
print("找到解决方案,状态序列:")
for s in solution:
print(s)
else:
print("无解")
五、关键点总结
1. 状态空间必须离散且有限,以便搜索算法遍历。
2. 动作的前置条件和效果需严格定义,避免非法状态。
3. BFS能保证最短路径,但若状态较多可改用DFS或启发式搜索。
4. 此题也可用简单逻辑推理直接求解(如直接移动凳子到香蕉下再爬上去),但通用方法是搜索。

查看详情

查看详情