B-Pour Water
一、问题描述
倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
Input
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
Output
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。
Sample Input
2 7 5
2 7 4
Sample Output
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success
Notes
如果你的输出与Sample Output不同,那没关系。对于某个"A B C"本题的答案是多解的,不能通过标准的文本对比来判定你程序的正确与否。 所以本题由 SPJ(Special Judge)程序来判定你写的代码是否正确。
二、思路与算法
首先,应该由题意辨别出这个问题是隐式图问题,可以使用BFS方法解决。
隐式图问题:仅给出初始节点、目标节点、生成子节点的约束条件(由题意隐含给出)。
本题中初始节点为A、B杯中都为0(杯空),目标节点为A、B中任意一方水量为C,约束条件为A、B中水量不能超过自身容量等。
编程思路为:输入并存储——>BFS搜索——>输出进行的所有操作。
输入并存储很简单,可用int型直接存储。
BFS搜索需要做抽象概念的转变,我们每次操作有6种可能:把A倒入B(AtoB)、把B倒入A(BtoA)、倒空A(emptyA)、倒空B(emptyB)、倒满A(fillA)、倒满B(fillB)。这六个动作类似于迷宫问题中一个点的周围四个点,它们分别通向6个相邻状态。
所以,我们利用队列queue,每次都check这六种动作,看是否可以达成目标节点。
输出进行的所有操作,类比于输出最短路径,我们也需要声明一些新变量,用于存储有关操作顺序的数据。
本次输出数据用string类存储,用vector数组存储所有要输出的内容,这样和用栈/队列等数据结构存储大同小异,选用顺手的存储即可。
至此,分析完成,按此思路编写的代码如下。(更详细的解释在注释中体现)
三、代码实现
#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<string>
using namespace std;
struct status{
int x,y;
string action; //记录为了达到这个状态,上一个状态进行了什么操作
status(){
} //重载构造函数
status(int xx,int yy){
x=xx; y=yy; }
bool operator < (const status &s)const{
if(x!=s.x){
return x<s.x; }
else{
return y<s.y; }
} //重载操作符(大小比较方法)
bool operator == (const status &s)