倒水问题 “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来实现,并且每一步都记录上一步的状态,并且利用vis数组来判断是否走过该状态,并且利用vis数组中的数字来记录该状态是怎么产生的。
代码实现
#include<iostream>
using namespace std;
#include<queue>
int vis[2000][2000]; //vis =不同的值对应不同的操作
struct P{
int A,B;
};
queue< P > q;
P SS[2000][2000]; //记录上一个状态
P bfs(int x,int y,int z) //x,y是杯子的容量
{
vis[0][0] = -1; //一开始2个都是空的
P a ;
SS[0][0].A = -1,SS[0][0].B=-1; //最开始的状态是没有上一个状态的,所以-1
a.A = 0,a.B = 0; //因为一开始是0, 0状态
q.push(a);
int a1,b1;
P ss;
while( !q.empty() )
{
ss = q.front();
a1 = ss.A;
b1 = ss.B;
q.pop();
for(int i=0;i<6;i++) //6种操作
{
if( i==0 ) //倒满A
{
if( vis[x][b1] == 0 )
{
vis[x][b1] =1;
P s1;
s1.A = x;
s1.B = b1;
SS[s1.A][s1.B].A = a1; //记录上一个状态
SS[s1.A][s1.B].B = b1;
if(s1.A == z || s1.B == z)
return s1;
q.push(s1);
}
}
else if(i==1) //倒满B
{
if(vis[a1][y] == 0)
{
vis[a1][y] =2;
P s2 ;
s2.A =a1;
s2.B =y;
SS[s2.A][s2.B].A = a1;
SS[s2.A][s2.B].B = b1;
if(s2.A==z || s2.B==z)
return s2;
q.push(s2);
}
}
else if(i==2) //A->B
{
P s3;
if( b1 < y) //b 不满
{
int b2 = y-b1;
if( a1 >= b2) //如果A有b2那么多来倒
{
int a2 = a1-b2;
s3.A = a2;
s3.B = y;
if( vis[s3.A][s3.B] == 0)
{
vis[s3.A][s3.B] =3;
SS[s3.A][s3.B].A = a1;
SS[s3.A][s3.B].B = b1;
if(s3.A==z || s3.B==z)
return s3;
q.push(s3);
}
}
else //A没有b2那么多
{
s3.A = 0;
s3.B = b1 + a1;
if( vis[s3.A][s3.B] ==0)
{
vis[s3.A][s3.B] =3;
SS[s3.A][s3.B].A = a1;
SS[s3.A][s3.B].B = b1;
if(s3.A==z || s3.B==z)
return s3;
q.push(s3);
}
}
}
}
else if(i==3) //b->A
{
P s4;
if( a1 < x )//A不满
{
int a2 = x-a1; //装满A要的水
if( a2 > b1 ) //如果b的水灌不满A
{
s4.A = a1+b1;
s4.B = 0;
if( vis[s4.A][s4.B] ==0)
{
vis[s4.A][s4.B] =4;
SS[s4.A][s4.B].A = a1;
SS[s4.A][s4.B].B = b1;
if(s4.A==z || s4.B==z)
return s4;
q.push(s4);
}
}
else
{
s4.A = x;
s4.B = b1 - a2;
if( vis[s4.A][s4.B] == 0)
{
vis[s4.A][s4.B] =4;
SS[s4.A][s4.B].A = a1;
SS[s4.A][s4.B].B = b1;
if(s4.A==z || s4.B==z)
return s4;
q.push(s4);
}
}
}
}
else if(i==4) //A->0
{
P s3;
s3.A = 0;
s3.B = b1;
if( vis[s3.A][s3.B] ==0)
{
vis[s3.A][s3.B] =5;
SS[s3.A][s3.B].A = a1;
SS[s3.A][s3.B].B = b1;
if(s3.A==z || s3.B==z)
return s3;
q.push(s3);
}
}
else if(i==5) //B->0
{
P s3;
s3.A = a1;
s3.B = 0;
if( vis[s3.A][s3.B] == 0)
{
q.push(s3);
vis[s3.A][s3.B] =6;
SS[s3.A][s3.B].A = a1;
SS[s3.A][s3.B].B = b1;
if(s3.A==z || s3.B==z)
return s3;
}
}
}
}
}
int main()
{
int A,B,C;
P pp[1001]; //用来提取状态的
while(cin>>A>>B>>C)
{
if( A>0 && B>=A && B>=C && B<=1000 )
{
//cout<< " **** "<<endl;
while (!q.empty())
q.pop();
P ppp= bfs(A,B,C);
int pi=0;
while( ppp.A!=-1 && ppp.B!=-1 ) //将过程提取出来到pp中
{
pp[pi] = ppp;
// cout<<pp[pi].A<<" "<<pp[pi].B<<endl;
ppp = SS[ppp.A][ppp.B];
pi++;
}
// cout<<"pi="<<pi<<endl;
for(int i=pi-1;i>=0;i--) //利用vis中值的不同来输出操作
{
//cout<<"**"<<endl;
// cout<< pp[i].A<<" "<<pp[i].B;
int v = vis[pp[i].A ][pp[i].B];
// cout<<" v= "<<v;
if( v == 1 )
cout<<"fill A"<<endl;
else if(v == 2)
cout<<"fill B"<<endl;
else if(v == 3)
cout<<"pour A B"<<endl;
else if(v==4)
cout<<"pour B A"<<endl;
else if(v==5)
cout<<"empty A"<<endl;
else if(v==6)
cout<<"empty B"<<endl;
}
cout<<"success"<<endl;
}
}
return 0;
}
收获
实现bfs,并要求记录过程的这种题目,我们可以使用vis数组进行判断,甚至还可以利用vis数组来记录进行了什么操作。