系列文章
补充发两篇文章记录一下之前用到的宽度优先算法
分啤酒问题:现有8升、5升、3升的容器各一个,均无任何度量标记,其中8升的容器装满啤酒,其他两个为空。要求用上述容器倒来倒去,分成两份4升的啤酒。
主要来介绍一下A*算法与该题目如何结合使用,并且使用python语言来实现它
可以看看这篇文章,类似关于算法的介绍网上很多
(x,y,z) 分别代表8,5,3升容器的啤酒量,
x∈(0,1,2,3,4,5,6,7,8),
y∈(0,1,2,3,4,5),
z∈(0,1,2,3),
初始状态为(8,0,0)
目标状态为(4,4,0)
这里因为题目的信息可以简化部分倒水的过程具体分析在代码注释里给出了解析,最终仅仅y倒入z与z倒入y需要进行讨论
因为一共就8升水,8升的杯子是无论如何都到不满的,所以比如5升杯子倒入8升杯子就不用讨论,直接 8升杯子+=5升杯子 5升杯子=0 这样既可
# -*- coding: utf-8 -*-
# @Time : 2020/10/15 16:26
# @Author : Tong Tianyu
# @File : chapter1_2.py
import queue
import numpy as np
# 定义啤酒类对象
class Beer:
def __init__(self):
self.x = 8 # 八升的水壶
self.y = 0 # 五升的水壶
self.z = 0 # 三升的水壶
self.state_space = np.zeros((9, 6, 4)) # 定义状态空间
self.q_tmp = queue.Queue() # 定义队列
self.final = [] # 定义结果
self.final_only_data = [[8, 0, 0]] # 便于操作的结果
def BFS(self):
# con = 1
self.q_tmp.put([8, 0, 0])
self.final.append([[8, 0, 0], 'none', [0]])
self.state_space[8][0][0] = 1
while len(self.q_tmp.queue) != 0:
a, b, c = self.q_tmp.get()
if a == 4 and b == 4:
continue
pre = [a, b, c]
# print('----------------', con, '------------------')
self.x, self.y, self.z = a, b, c
self.Pour_X_To_Y()
self.update(pre, a, b, c, 'Pour_X_To_Y')
self.Pour_X_To_Z()
self.update(pre, a, b, c, 'Pour_X_To_Z')
self.Pour_Y_To_X()
self.update(pre, a, b, c, 'Pour_Y_To_X')
self.Pour_Y_To_Z()
self.update(pre, a, b, c, 'Pour_Y_To_Z')
self.Pour_Z_To_X()
self.update(pre, a, b, c, 'Pour_Z_To_X')
self.Pour_Z_To_Y()
self.update(pre, a, b, c, 'Pour_Z_To_Y')
# con += 1
return self.final, self.final_only_data
def update(self, pre, a, b, c, name):
if self.state_space[self.x][self.y][self.z] == 0:
self.state_space[self.x][self.y][self.z] = 1
self.q_tmp.put([self.x, self.y, self.z])
self.final_only_data.append([self.x, self.y, self.z])
self.final.append([[self.x, self.y, self.z], name, pre])
self.x, self.y, self.z = a, b, c
def Pour_X_To_Y(self):
'''
将8升杯x的水倒入5升杯y中
因为总共8升的水,就算3升的杯子装满了,剩下的水也还有5升
所以 x + y >= 5
'''
self.x -= 5 - self.y
self.y = 5
return True
def Pour_X_To_Z(self):
'''
将8升杯x的水倒入3升杯z中
因为总共8升的水,就算5升的杯子装满了,剩下的水也还有3升
所以 x +z >= 3
'''
self.x -= 3 - self.z
self.z = 3
return True
def Pour_Y_To_X(self):
'''
将5升杯y的水倒入8升杯x中
分析一下 5升杯的水全倒入8升杯也装不满
'''
self.x += self.y
self.y = 0
return True
def Pour_Y_To_Z(self):
'''
将5升杯y的水倒入3升杯z中
这里要讨论了
'''
if self.y + self.z >= 3: # 倒满三升杯
self.y -= 3 - self.z
self.z = 3
else:
self.z += self.y
self.y = 0
return True
def Pour_Z_To_X(self):
'''
将3升杯z的水倒入8升杯x中
同理,不用讨论
'''
self.x += self.z
self.z = 0
return True
def Pour_Z_To_Y(self):
'''将3升杯z的水倒入5升杯y中'''
if self.z + self.y >= 5:
self.z -= 5 - self.y
self.y = 5
else:
self.y += self.z
self.z = 0
return True
if __name__ == '__main__':
beer = Beer()
final_list, tmp_list = beer.BFS()
print(final_list)
result = []
for i in range(len(final_list)):
if i == 0:
continue
data = final_list[i]
print('每行的数据为:', data)
pre = data[2]
print('当前的父节点为:', pre)
pre_index = tmp_list.index(pre)
print('当前父节点在列表中的位置为:', pre_index)
result = final_list[pre_index][-1]
print('当前父节点的路径为:', result)
# md这里被深浅复制搞死了
a = result.copy()
a.append(i)
final_list[i][-1] = a
print('*********************************************')
def output(order):
print('x' + '\t' + 'y' + '\t' + 'z' + '\t' + 'method')
for i in order:
print(*final_list[i][0], sep='\t', end='\t')
print(final_list[i][1])
for i in range(len(tmp_list)):
con = 0
if tmp_list[i] == [4, 4, 0]:
print(f'-------------方法{con}--------------')
order = final_list[i][-1]
output(order)
con += 1