三个水壶的问题
有一个充满水的8品脱的水壶和两个空水壶(容积分别是5品脱和3品脱)。通过将水壶完全倒满水和将水壶的水完全倒空这两种方式,在其中的一个水壶中得到4品脱的水。
这道问题的思想就是对每一个状态进行扩展,并记录其前一个状态,然后放到list
中记录(在记录过程中应判断这个状态之前是否已经被拓展过了),并以二叉树的数据结构的眼光看待这个list
,为了更快地找到有4
状态的节点,选择广度优先遍历的方式,借用队列的数据结构可以实现广度优先遍历。
定义节点的结构
class Node:
def __init__(self, per=None, status=[8, 0, 0]): # per 指向上一个节点,status表示当前状态
self.per = per
self.status = status
def __str__(self): # 调用print函数时会调用此接口,将其返回值打印
return '{}'.format(self.status)
倒水的动作
def pour(cur_node, old_list, new_list):
max_list = [8, 5, 3] # 定义出每一个瓶子的最大容量
r_list = cur_node.status # 先存储住当前状态
# 认为是将瓶子 i 倒入到瓶子 j 中
for i, j in ((0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 2)):
n_list = r_list.copy()
# 判断 i 是否有足够的的水将 j 倒满。如果有,倒满 j;如果没有,倒空 i
# max_list[j] - r_list[j] 这个式子的结果为 j 还差多少水能够装满
if r_list[i] > max_list[j] - r_list[j]: # i 足够倒满 j
n_list[j] = max_list[j] # 将 j 倒满
n_list[i] = r_list[i] - (max_list[j] - r_list[j])
else: # i 不足够倒满 j,即倒空 i
n_list[i] = 0
n_list[j] = r_list[i] + r_list[j]
# 这一步判断当前的 n_list 的状态是否已经被考虑过了
flag = True
for node in old_list:
if node.status == n_list:
flag = False
# 如果未考虑过则将 n_list 添加到二叉树中
if flag:
new_node = Node(cur_node, n_list)
new_list.append(new_node)
广度优先遍历
def print_ret(node):
ret = []
while node.per != None:
ret.append(node.status)
node = node.per
ret.append(node)
for i in range(len(ret) - 1, -1, -1):
print('第{0}步:{1}'.format(len(ret) - i, ret[i]))
def BFS_node(root):
old_list = []
new_list = [root]
while new_list != []:
cur_node = new_list.pop(0)
if 4 in cur_node.status:
print_ret(cur_node)
return
old_list.append(cur_node)
pour(old_list[len(old_list) - 1], old_list, new_list)
root = Node()
BFS_node(root)
第1步:[8, 0, 0]
第2步:[3, 5, 0]
第3步:[3, 2, 3]
第4步:[6, 2, 0]
第5步:[6, 0, 2]
第6步:[1, 5, 2]
第7步:[1, 4, 3]