题目描述:
倒水问题 "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列开始,不应该有空行或任何尾随空格。
思路:
这不是一道图论的题目,但是可以通过广度优先搜索的方法来解决。在已知当前A B两个杯子的状态后,可以选择下一个状态,但是下一个状态应该是之前没有出现过的,否则将进入死循环,这样没有任何意义。因此,广度优先搜索的思路就形成了,首先确定初始状态:A满B空或者A空B满,将两个状态分别进队,然后开始搜索即可,在出现A或B杯中的水量为C时,搜索停止。
搜索的具体过程:每次从队列取出一个结构体,当前结构体记录了此时A,B两个杯子的状态,对于A杯:1、判断是否可以将水倒入B中(条件是A不空且B不满),如果可以,则do!2、判断是否可以将A中的水倒掉(条件是A不空),如果可以,则do! 3、判断是否可以将A中到满水(条件是A不满),如果可以,则do! 对于B杯,同理与A杯。根据以上的规则,由当前的状态推出了下个状态,如果下个状态未出现过(由一个二维数组判断即可),则将其进队。当搜索到A或B杯中的水量为C时,搜索停止即可。
总结:
这是一道隐式图的问题,看似复杂,但可以通过广度优先搜索的方式,搜索枚举每个状态。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
bool flag[1010][1010];
int ansa[1010][1010],ansb[1010][1010],outa[10100],outb[10100],sum;
int A,B,C;
string s[5000];
struct node
{
int a;
int b;
}x;
queue<node> q;
void out()
{
int a,b,nexta,nextb;
for(int i=sum;i>1;i--)
{
if(i==sum)
{
if(outa[i]==A)
cout<<"fill A"<<endl;
else
cout<<"fill B"<<endl;
//continue;
}
a=outa[i],b=outb[i];
nexta=outa[i-1],nextb=outb[i-1];
if(nexta!=a&&nextb!=b)
{
if(nexta==0||nextb==B)
cout<<"pour A B"<<endl;
else cout<<"pour B A"<<endl;
}
else if(nexta==a&&nextb!=b)
{
if(nextb==0)
cout<<"empty B"<<endl;
else cout<<"fill B"<<endl;
}
else
{
if(nexta==0)
cout<<"empty A"<<endl;
else cout<<"fill A"<<endl;
}
}
cout<<"success"<<endl;
}
void output(int a,int b)
{
int lasta,lastb;sum=0;
while(1)
{
int t=a;
outa[++sum]=a;
outb[sum]=b;
a=ansa[a][b];
b=ansb[t][b];//获取上次状态
if(a==A&&b==0)
{
outa[++sum]=A;
outb[sum]=0;
break;
}
if(a==0&&b==B)
{
outa[++sum]=0;
outb[sum]=B;
break;
}
}
out();
}
void bfs()
{
while(!q.empty()) q.pop();
memset(ansa,0,sizeof(ansa));
memset(ansb,0,sizeof(ansb));
memset(flag,0,sizeof(flag));
x.a=A;
x.b=0;
flag[A][0]=1;
q.push(x);
x.a=0;
x.b=B;
flag[0][B]=1;
q.push(x);
while(!q.empty())
{
int nowa=q.front().a;
int nowb=q.front().b;
q.pop();node tmp;
if(nowa==C||nowb==C)
{
output(nowa,nowb);
return;
}
if(nowa!=A)//a可以倒满
{
tmp.a=A;tmp.b=nowb;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
if(nowa!=A&&nowb>0)//b往a中倒
{
int cha=A-nowa;
if(cha>nowb)//b倒入a且a还不满
{
tmp.a=nowa+nowb;
tmp.b=0;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
else//b倒入a,a满
{
tmp.a=A;
tmp.b=nowb-cha;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
}
if(nowb!=B)//将b倒满
{
tmp.a=nowa;tmp.b=B;
if(!flag[tmp.a][tmp.b])//将b倒满
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
if(nowa>0&&nowb!=B)//a往b中倒
{
int cha=B-nowb;
if(nowa<cha)//a倒入b后,a空
{
tmp.a=0;
tmp.b=nowb+nowa;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
else//a倒入b后,b满
{
tmp.a=nowa-cha;
tmp.b=B;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
}
if(nowa>0)//a倒空
{
tmp.a=0;tmp.b=nowb;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
if(nowb>0)//b倒空
{
tmp.a=nowa;tmp.b=0;
if(!flag[tmp.a][tmp.b])
{
ansa[tmp.a][tmp.b]=nowa;
ansb[tmp.a][tmp.b]=nowb;
flag[tmp.a][tmp.b]=1;
q.push(tmp);
}
}
}
}
int main()
{
while(scanf("%d%d%d",&A,&B,&C)!=EOF)
{
if(A==C)
{
cout<<"fill A"<<endl<<"success"<<endl;
continue;
}
else if(B==C)
{
cout<<"fill B"<<endl<<"success"<<endl;
continue;
}
bfs();
}
}