题意:给出了两个瓶子的容量A,B, 以及一个目标水量C,对A,B可以进行如下操作:
FILL(i) 将瓶i装满水
DROP(i) 将瓶i倒空
POUR(i,j) 将瓶i中的水倒入瓶j,此操作后要么瓶j装满水,要么瓶i为空
求至少要几次操作能使A或者B装的水为C,并输出具体操作
分析:可以从6个方面bfs,因为要输出具体操作,可以用数组模拟队列,
并记录前一次操作的状态,最后再回溯路径
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct stu
{
int step,a,b,pos;
}que[1010];
int a,b,c,ope[1010],step[1010],x,y,front,rear;
bool vis[105][105];
void fill(int i)
{
if(i==1)
x=a;
else
y=b;
}
void drop(int i)
{
if(i==1)
x=0;
else
y=0;
}
void pour(int i,int j)
{
if(i==1){
if(x+y>=b){
x-=b-y;
y=b;
}
else{
y+=x;
x=0;
}
}
else{
if(x+y>=a){
y-=a-x;
x=a;
}
else{
x+=y;
y=0;
}
}
}
void is_push(int step,int num)
{
if(!vis[x][y]){
que[rear].a=x;
que[rear].b=y;
que[rear].step=step+1; //记录步数
que[rear].pos=front; //记录前一次状态
ope[rear++]=num; //当前的操作
vis[x][y]=true; //标记为已访问
}
}
int bfs()
{
int i,num,q[7]={0,110,120,210,220,312,321}; //q数组用来标记执行的操作,以便最后输出
struct stu t;
front=0;
rear=1;
memset(vis,0,sizeof(vis));
vis[0][0]=1;
que[front].a=que[front].b=0;
que[front].step=0;
while(front<rear){
t=que[front];
if(t.a==c||t.b==c){
num=t.step;
step[num]=front;
num--;
while(num){
step[num]=que[step[num+1]].pos;
num--;
}
return t.step;
}
for(i=1;i<=6;i++){
x=t.a;
y=t.b;
switch(i){
case 1:fill(1);break;
case 2:fill(2);break;
case 3:drop(1);break;
case 4:drop(2);break;
case 5:pour(1,2);break;
case 6:pour(2,1);
}
is_push(t.step,q[i]);
}
front++;
}
return -1;
}
int main()
{
int sum,i,k;
while(scanf("%d%d%d",&a,&b,&c)!=EOF){
sum=bfs();
if(sum==-1){
printf("impossible\n");
continue;
}
printf("%d\n",sum);
for(i=1;i<=sum;i++){
k=ope[step[i]];
if(k/100==1)
printf("FILL(%d)\n",k/10%10);
else if(k/100==2)
printf("DROP(%d)\n",k/10%10);
else if(k/100==3)
printf("POUR(%d,%d)\n",k/10%10,k%10);
}
}
return 0;
}