题意概述
"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列开始,不应该有空行或任何尾随空格。
思路
全部操作共有六种,分别是fill A
,fill B
,empty A
,empty B
,pour A B
,pour B A
。
整体思路是:
1.用一个结构体记录杯子a、b的状态并重载比较操作。
struct Status
{
int a,b;
bool operator<(const Status &s) const
{
return a!=s.a ? a<s.a : b<s.b;
}
};
2.用map记录杯子a和b当前和上一步的状态,利用队列实现bfs。
3.在bfs函数内部,每次取队首元素,首先判断是否得到容量为C的水(特判终点)。然后分四大类情况讨论:倒空a杯b杯不变,倒空b杯a杯不变,续满a杯,续满b杯。后两种情况又需考虑a杯和b杯当前水量的总和与要续满的杯的容量的关系,分为倒满一杯或倒空另一杯。
4.每种情况下,都需要更新记录状态的map。
5.最后用递归输出解决方案,输出前,需要增加一个输出判断的函数print_judge( ),因为在bfs中我们只是记录了每一步的状态,还需要根据前后状态的变化输出对应的操作。
void print_judge(Status &s,Status &t)
{//通过判断倒水操作的前后状态来判断进行了什么操作
if(s.a==t.a)
{//a杯没变
if(t.b==B) //操作之后b杯是满的
cout<<"fill B"<<endl;
else
cout<<"empty B"<<endl;
}
else if(s.b==t.b)
{//b杯没变
if(t.a==A)
cout<<"fill A"<<endl;
else
cout<<"empty A"<<endl;
}
else{
if(t.a<s.a) //a杯少了
cout<<"pour A B"<<endl;
else
cout<<"pour B A"<<endl;
}
}
代码
#include <iostream>
#include<queue>
#include<map>
using namespace std;
struct Status
{
int a,b;
bool operator<(const Status &s) const
{
return a!=s.a ? a<s.a : b<s.b;
}
};
queue<Status> Q;
map<Status, Status> from;//map用来记录a/b杯水的上一状态和当前状态
int A,B,C;
//string s[]={"fill A","fill B","empty A","empty B","pour A B","pour B A"};
void print_judge(Status &s,Status &t)
{//通过判断倒水操作的前后状态来判断进行了什么操作
if(s.a==t.a)
{//a杯没变
if(t.b==B) //操作之后b杯是满的
cout<<"fill B"<<endl;
else
cout<<"empty B"<<endl;
}
else if(s.b==t.b)
{//b杯没变
if(t.a==A)
cout<<"fill A"<<endl;
else
cout<<"empty A"<<endl;
}
else{
if(t.a<s.a) //a杯少了
cout<<"pour A B"<<endl;
else
cout<<"pour B A"<<endl;
}
}
//递归输出每步操作
void print(Status &p)
{
if ( from.find(p) == from.end() || (p.a == 0&&p.b==0) )
{
return;
}
print(from[p]); // 递归
print_judge(from[p],p);
}
void refresh(Status &s, Status &t)
{
if ( from.find(t) == from.end() )
{ // 特判合法,加入队列
from[t] = s;
Q.push(t);
}
}
void bfs()
{
// 起点, 两杯水都空
Status s,t; s.a=0; s.b=0;
Q.push(s);
while (!Q.empty())
{
// 取队首
s = Q.front(); Q.pop();
// 特判到达终点
if (s.a == C || s.b == C) {
print(s); // 输出方案
return;
}
// 倒空 a 杯的水
if (s.a > 0) {
t.a = 0; // 倒空
t.b = s.b;// b 杯不变
refresh(s, t);
}
// 同理,倒空 b 杯的水
if (s.b > 0) {
t.b = 0; // 倒空
t.a = s.a;// a 杯不变
refresh(s, t);
}
// a 杯未满,续满 a 杯
if (s.a < A)
{
// 续满 a 杯
t.a = A;
t.b = s.b;
refresh(s, t);
// 考虑倒入
if (s.b != 0)
{
if (s.a + s.b <= A)
{
t.a = s.a + s.b;
t.b = 0;
refresh(s, t);
} else
{
t.a = A;
t.b = s.a + s.b - A;
refresh(s, t);
}
}
}
// 同理,b 杯未满,续满 b 杯
if (s.b < B)
{
t.a = s.a;
t.b = B;
refresh(s, t);
if (s.a != 0)
{
if (s.a + s.b <= B)
{
t.a = 0;
t.b = s.a + s.b;
refresh(s, t);
} else
{
t.a = s.a + s.b - B;
t.b = B;
refresh(s, t);
}
}
}
}
}
int main()
{
while(cin>>A>>B>>C)
{
while(!Q.empty()){
Q.pop();
}
from.clear();
bfs();
cout<<"success"<<endl;
}
return 0;
}