有三个已知容量的杯子A,B,C,利用A杯和B杯来回倒水使任意一个杯子正好包含C单位的水。
“fill A ”表示倒满A杯,“empty A”表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或把A杯倒空。
输出整个倒水过程,最后输出“ success ”。
倒水的过程其实是A杯和B杯从一个状态变化到另一个状态,最后达到一个目标状态的过程。可以把每一个状态抽象为一个点,x代表A杯,y代表B杯。整个过程简化为从(0,0)变化到(x,C)或(C,y)。
利用bfs方法求解,当前节点一步操作可以走到哪些点取决于题目操作。例如当前点是(a,b),则一步操作可以走到的点有:倒空A杯的水(0,b),倒空B杯的水(a,0),倒满A杯(A,b),倒满B杯(a,B),A杯倒向B杯(0,a+b)或(a+b-B,B),B杯倒向A杯(a+b,0)或(A,a+b-A)。
记录每个点的前序点,最后根据两点的状态求出当前操作。
求解从一个状态的到另一个状态的过程问题,可以考虑bfs方法,并且可以保证这个过程最简短。
一定要注意开的二维数组的大小是[A+1][B+1],因为有倒空和倒满两种状态,否则会发生数组越界。
输出过程print也可以不存入数组,递归到起点然后再输出也是一个很好的方法。输出时判断两个状态之间的操作过程judge此处写的是复杂的。
#include
#include
#include
using namespace std;
struct point
{
int a;
int b;
point(int a, int b)
{
this->a = a;
this->b = b;
}
point(){}
};
point** before; //(当前状态,前一状态)
queue<point> way;
void judge(point& s, point& t, int A, int B)//判断操作
{
if (s.a > 0 && t.a == 0 && t.b == s.b)
cout << "empty A" << endl;
else if (t.a == s.a && s.b > 0 && t.b == 0)
cout << "empty B" << endl;
else if (s.a < A && t.a == A && t.b == s.b)
cout << "fill A" << endl;
else if (s.b < B && t.b == B && t.a == s.a)
cout << "fill B" << endl;
else if (s.a < A && s.b != 0)
cout << "pour B A" << endl;
else if (s.b < B && s.a != 0)
cout << "pour A B" << endl;
}
void print(point t, int A, int B)//输出过程
{
point* path;
path = new point[(A + 1) * (B + 1)];
int m = 0;
while (t.a != 0 || t.b!=0)
{
path[m] = t;
t = before[t.a][t.b];
m++;
}
path[m] = t;
m++;
for (int i = m - 1; i >0 ; i--)
judge(path[i], path[i - 1], A, B);
cout << "success" << endl;
}
void change(point& s, point& t)//记录前序点
{
if (before[t.a][t.b].a == -1)
{
before[t.a][t.b] = s;
way.push(t);
}
}
void bfs(int A, int B, int C)
{
point p(-1, -1);
for (int i = 0; i <= A; i++)//初始化前序点数组
for (int j = 0; j <= B; j++)
before[i][j] = p;
while (!way.empty())//清空队列
{
way.pop();
}
point s, t;
s.a = 0;
s.b = 0;
way.push(s);
before[s.a][s.b] = s;
while (!way.empty())
{
s = way.front();
way.pop();
if (s.a == C || s.b == C)//特判终点
{
print(s, A, B);
return;
}
//倒空a杯的水
if (s.a > 0)
{
t.a = 0;
t.b = s.b;
change(s, t);
}
//倒空b杯的水
if (s.b > 0)
{
t.a = s.a;
t.b = 0;
change(s, t);
}
//a杯未满,蓄满a杯
if (s.a < A)
{
t.a = A;
t.b = s.b;
change(s, t);
//考虑倒入
if (s.b != 0)//pour B A
{
if (s.a + s.b <= A)
{
t.a = s.a + s.b;
t.b = 0;
change(s, t);
}
else//倒满a杯
{
t.a = A;
t.b = s.a + s.b - A;
change(s, t);
}
}
}
//b杯未满,蓄满b杯
if (s.b < B)
{
t.a = s.a;
t.b = B;
change(s, t);
//考虑倒入
if (s.a != 0)//pour A B
{
if (s.a + s.b <= B)
{
t.a = 0;
t.b = s.a + s.b;
change(s, t);
}
else
{
t.a = s.a + s.b - B;
t.b = B;
change(s, t);
}
}
}
}
}
int main()
{
int A, B, C;
while (cin >> A)
{
cin >> B;
cin >> C;
before = new point * [A + 1];
for (int i = 0; i < A + 1; i++)
before[i] = new point[B + 1];
bfs(A, B, C);
}
}