这个问题用bfs怎么判断啊?
题目:
有4个红酒瓶子,它们的容量分别是:9升, 7升, 4升, 2升
开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着。
允许把酒从一个瓶子倒入另一个瓶子,但只能把一个瓶子倒满或把一个瓶子倒空,不能有中间状态。这样的一次倒酒动作称为1次操作。
假设瓶子的容量和初始状态不变,对于给定的目标状态,至少需要多少次操作才能实现?
本题就是要求你编程实现最小操作次数的计算。
输入:最终状态(逗号分隔)
输出:最小操作次数(如无法实现,则输出-1)
例如:
输入:
9,0,0,0
应该输出:
0
输入:
6,0,0,3
应该输出:
-1
输入:
7,2,0,0
应该输出:
2
怎么判断结束的状态啊??一种情况是有最少的步骤好判断,还一种
是没有最少的步骤(即输出-1),怎么判断啊?
[解决办法]
队列是一个抽象的说法,具体实现的时候用集合set一类能快速增删和查找的数据结构比较方便。
两个集合,open, close.
初始化 把[9,0,0,0]放入open
重复直到open为空
取open的第一个元素s,把s从open中去掉,加入到close.
从s产生所有一次操作能产生的状态。
对每个这样长生的状态t, 如果新状态不存在于open和close中间,把它加入到open, 否则抛弃之
这就是状态空间搜素的一般算法。每一个[9,0,0,0]这样的状态(我注意到你也是用状态来称呼它的),都是状态空间的一个点。
从s产生所有一次操作能产生的状态的方法。以[9,0,0,0]为例
唯一可做的是往2,3,4倒酒,所以只有三个[2,7,0,0],[5,0,4,0],和[7,0,0,2]。
我们再试着做一个例子,就以[2,7,0,0]为例,能产生的子状态
倒第一瓶的 [0,7,2,0], [0,7,0,2]
倒第二瓶的 [9,0,0,0], [0,3,4,0],[0,5,0,2]
这5种。注意到[9,0,0,0]这个状态就是我们的初始状态,如果我们能不检查到其已经被处理过(存在于close集合), 又把它添加到open集合中,那这个问题永远做不完的...
看看我们需要的操作,要往容器中添加元素,要从容器中删除元素,还要检查一个元素是否已经存在于容器中,数据结构意义上的队列(或者堆栈)可以满足我们增删元素的要求(摊薄常数时间),但存在性检查是线性时间的,总体效率会大大低于所有操作都是对数时间的set数据结构。
如果你用c++, set或unordered_set是你的当然选择。算法的描述我上面写了,非常单纯的。