题目链接

紫书第七章例题 [Cloned] - Virtual Judge (csgrandeur.cn)

分析

三个杯子,状态用来描述系统中某时刻所有个体特定值。 如有一状态(6,0,0)和(3,3,0),可从前一个状态通过将杯子a中的水倒入杯子b中转移得到,也就是说这两个状态存在(ab)的边。

而BFS可以理解为,从第一个点计算出它可以有的边,以及经过该便走到的状态,直接走过去,类似spfa。

倒水问题就从起始状态出发,用队列BFS枚举所有状态,遇到满足要求的就存下,最后从存下来答案中找最优的。

枚举时可以借鉴djikstra的优化思路,用priori_queue,以总倒水量为排序标准这样向队列中添加新计算出的状态时,就会从总倒水量最少的状态开始,当枚举到后面的状态时,因不优于之前搜过的状态解而快速剪枝。

对于每个状态的三个杯子,abc,a可能到给bc,b也可能倒给a,c,故用2层 for(int i = 0; i < 3; i ++) for(int j = 0; j < 3; j ++) 当 i != j 时就去倒水并将得出的新状态添加进队列

记录每杯水的容量不用三个变量,可以用一个cap[3]记录,为了判断当前状态是否已经被枚举过,用st[N][N][N]记录,但实际上可以用st[N][N],因为前两个确定时,最后一个只有一种可能(总量不变)

答案是最接近d的最小倒水量 假设一定存在d,则可以直接用ans,在队列弹出时,判断当前状态中是否有杯子的水量为d,有则直接 更新ans并退出程序。 那么现在去掉假设,需要找到d 且最接近d的答案。 也就是说将判断条件改为 (d - v[i] < res) res =d - v[i]; 成立时说明当前水量比之前的res更接近d,更新答案,最终结果输出为d - res