题目:
小明给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作
FILL(i) 将第i个容器从水龙头里装满(1 ≤ i ≤ 2);
DROP(i) 将第i个容器抽干
POUR(i,j) 将第i个容器里的水倒入第j个容器(这次操作结束后产生两种结果,一是第j个容器倒满并且第i个容器依旧有剩余,二是第i个容器里的水全部倒入j中,第i个容器为空)
现在要求你写一个程序,来找出能使其中任何一个容器里的水恰好有C升,找出最少操作数并给出操作过程
Input
有且只有一行,包含3个数A,B,C(1<=A,B<=100,C<=max(A,B))
Output
第一行包含一个数表示最小操作数K
随后K行每行给出一次具体操作,如果有多种答案符合最小操作数,输出他们中的任意一种操作过程,如果你不能使两个容器中的任意一个满足恰好C升的话,输出“impossible”
Sample
Input
3 5 4
Sample Output
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)
解
思路比较容易想到;就是用bfs有6个方向,具体细节看代码
ac代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
#include<string>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int A,B,C;
string print[6]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
typedef struct
{
int A,B;
int pre;
int op; //记录该点经行的操作
}status;
status a[10005];//记录路径
int cnt=1; //索引作用
int len;
status bfs()
{
status first;
first.A = 0;
first.B = 0;
first.pre=-1; //标记头节点
a[0] = first;
for(int k=0;;k++)
{
if(k>=cnt) break; //说明无新增
for(int i=0;i<6;i++)
{
status New;
New = a[k];
New.pre = k;
New.op = i;
if(i==0)
{
if(New.A==A) continue;
//加continue的意思是表明该点已访问,不必在进行后续记录操作
New.A = A;
}
if(i==1)
{
if(New.B==B) continue;
New.B = B;
}
if(i==2)
{
if(New.A==0) continue;
New.A = 0;
}
if(i==3)
{
if(New.B==0) continue;
New.B = 0;
}
if(i==4)
{
int pour = min(New.A,B-New.B);
if(pour==0) continue;
New.A -=pour;
New.B +=pour;
}
if(i==5)
{
int pour = min(New.B,A-New.A);
if(pour==0) continue;
New.A +=pour;
New.B -=pour;
}
if(New.A==C||New.B==C)
{
return New;
}
//一下为记录路径的操作
bool flag = false;
for(int j=0;j<cnt;j++)
{
if(a[j].A==New.A&&a[j].B==New.B)
{
flag = true;
break;
}
}
if(!flag) a[cnt++]=New;
}
}
status loser;
loser.pre =-2; //标记没有找到
return loser;
}
void coutt(status New)
{
if(New.pre==-2)
{
cout<<"impossible\n"<<endl;
return ;
}
if(New.pre == -1)
//找到头节点返回
{
cout<<len<<endl;
return;
}
else
{
len++;
coutt(a[New.pre]);
cout<<print[New.op]<<endl;
}
return;
}
int main()
{
scanf("%d%d%d",&A,&B,&C);
coutt(bfs());
return 0;
}