B - Pour Water
-
题目:A,B为两水杯量程,C为所求量程。倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
-
解题思路:涉及到隐式BFS,自定义结构体node,记录每个结点的两个水杯值以及需要输出的字符串。从(0,0)开始进行BFS,在满足条件的情况下分别执行把A倒满,B倒满,A倒空,B倒空,把A倒给B以及把B倒给A,作为BFS的第一层。例用map将每个结点的上一个结点记录在from中,并将新出现的情况用mp进行标记,未被标记的结点加入队列作为BFS的下一层,每次让s等于队首元素,继续执行六个操作,直到队列为空或是已经得出目标容量C为止,跳出循环。从(0,0)开始递归输出结果,直到from.end,输出结束。
-
代码实现:
#include <iostream>
#include <queue>
#include <string>
#include <map>
using namespace std;
int A,B,C;
struct node
{
int x,y;
string choice;
bool operator<(const node &s) const
{
return x!=s.x ? x<s.x : y<s.y;
}
};
node s,t;
queue<node> Q;
map<node,node> from;
map<node,bool> mp;
//更新s,t值
void refresh(node s,node t)
{
if(from.find(t)==from.end())
{
from[t] = s;
Q.push(t);
}
}
void print(node &t)
{
if (from.find(t) != from.end()) {
print(from[t]);
cout<<t.choice<<endl;
}
}
void fillA(node s,node t)
{
t.x=A;
t.y=s.y;
if(mp[t]==0){
mp[t]=1;
t.choice="fill A";
refresh(s,t);
}
else
return;
}
void fillB(node s,node t)
{
t.x=s.x;
t.y=B;
if(mp[t]==0){
mp[t]=1;
t.choice="fill B";
refresh(s,t);
}
else
return;
}
void emptyA(node s,node t)
{
t.x=0;
t.y=s.y;
if(mp[t]==0){
mp[t]=1;
t.choice="empty A";
refresh(s,t);
}
else
return;
}
void emptyB(node s,node t)
{
t.x=s.x;
t.y=0;
if(mp[t]==0){
mp[t]=1;
t.choice="empty B";
refresh(s,t);
}
else
return;
}
void AtoB(node s,node t)
{
t.x=max(s.x+s.y-B,0);
t.y=min(s.x+s.y,B);
if(mp[t]==0){
mp[t]=1;
t.choice="pour A B";
refresh(s,t);
}
else
return;
}
void BtoA(node s,node t)
{
t.x=min(s.x+s.y,A);
t.y=max(s.x+s.y-A,0);
t.choice="pour B A";
if(mp[t]==0){
mp[t]=1;
refresh(s,t);
}
else
return;
}
int main()
{
while(cin>>A>>B>>C)
{
mp.clear();
from.clear();
while(!Q.empty())
Q.pop();
s.x=0; s.y=0; t.x=0; t.y=0;
mp[s]=1;
Q.push(s);
bool flag=false;
while(!Q.empty())
{
s=Q.front();
Q.pop();
if(s.x==C||s.y==C)
{
flag=true;
print(s);
break;
}
fillA(s,t);
fillB(s,t);
emptyA(s,t);
emptyB(s,t);
AtoB(s,t);
BtoA(s,t);
}
if(flag)
cout<<"success"<<endl;
}
return 0;
}