问题背景
首先给定两个杯子,体积分别问max_X、max_Y。杯子里当前分别有水量x、y。允许的操作有装满一个杯子、倒空一个杯子、将一个杯子中的水倒入另一个杯子。
现在想要通过这两个杯子,获取指定体积的水,需要经过哪些操作?
比如:两个杯子体积分别为90L和50L,现杯中水量为0L和0L,想要得到60L的水,需要经过哪些操作?
算法思路
- 假设当前水杯状态分别为(x,y)。即分别有x升水和y升水。那么只通过一步操作,写出所有可能的下一步水杯状态。
def next_step(x, y, max_X, max_Y):
return {
(0, y): '倒空x',
(x, 0): '倒空y',
(x + y - max_Y, max_Y) if x + y >= max_Y else (0, x + y): 'x倒入y中',
(max_X, x + y - max_X) if y + x >= max_X else (x + y, 0): 'y倒入x中',
(max_X, y): '装满x',
(x, max_Y): '装满y'
}
- 通过递归调用,寻找可能的路径
def search_solution(capacity1, capacity2, goal, start=(0, 0)):
paths = [ [('init', start)] ]
explored = set() # 存放已经出现过得状态。对于已经出现过得状态,说明已经探索过了,就没必要重复探索
while paths: # 遍历所有可能的路径
path = paths.pop(0) # 取一条路径
frontier = path[-1] # 取路径最末端的节点
(x, y) = frontier[-1] # 获取该节点的状态
for state, action in next_step(x, y, capacity1, capacity2).items(): # 遍历该状态下,下一步所有可能的状态
# ic(frontier, state, action)
if state in explored: continue # 如果下一步的状态已经探索过了,就跳过
new_path = path + [ (action, state) ] # 将下一步状态,添加到当前路径的末端
if goal in state:
return new_path # 如果找到目标状态,就返回该路径
else:
paths.append(new_path) # 如果没找到目标状态,就将该路径添加到路径探索列表中
explored.add(state) # 并将该状态添加到已探索状态中
return None
-
调用运行
search_solution(90, 50, 60, (0, 0))
总结延伸
倒水问题,是一个经典的将实际问题,转化为代码的小练习。经过锻炼,逐渐熟悉python语法和算法处理,后面就可以提升难度,进入更高一个层次的算法训练了。