给你两个容器,分别能装下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的题,不但要找出最短路径(到达c的最短路),还要记录路径过程,这里用的结构的特性定义了数组pre[][],用pre[x][y]中的x,y来表示两个容器分别到达x,y两种状态,用pre[x][y].x和pre[x][y].y和pre[x][y].step来表示下x,y的状态是由pre[x][y].x和pre[x][y].x通过step来到达,通过一个递归函数pr来输出操作路径,这个递归函数先递归到最后一层到x,y都为零,这是结束标志,再从里到外一层一层的输出,最后便是从先到后的操作方法输出,(这是一种用递归函数从外递到内,内也就是最先的操作方法,再从外到内一层一层的输出),对还有,再进行bfs时利用vis[][]剪枝,到一种状态时,判断是不是第一次到达,如果是就利用vis[][]标记一下这个状态到达过,因为在bfs里第一次到达这个状态也是最快到达这个状态,也就是通过最少的操作数到达的路径,其后面到达这个1状态的就可以舍去了,因为肯定后面到达此状态的操作数比第一个到达的多,所以舍去,如果是并列到达一种状态,随意取一个即可,都是通过同样的操作数到达,而且题目只要求随意一写出一个即可,通过剪枝才不会时间超限;
通过这几天对搜索的学习,总结一下:对于dfs,主要是对于一个点直接递归到最低,如果不行,再对另一个方向递归到低;而对于bfs,是对一个点可以到达的所有的状态,进行列举,把状态列出来放入队列中,每去一个点都要都周围中的所有状态进行列举放入队列,最后指导搜到结果,bfs一般用来搜索最短路径,如此题,bfs通常使用到队列,而且队列里都是pair或者自己的写的结构;对于搜索较为难一些的是需要剪枝的;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
struct node
{
int x,y;
int step;
}pre[10001][10001];
int vis[102][102],a,b,c,now[3],limt[3],tt[3],ans1,ans2;
node t,d;
int bfs()
{
t.x=now[0];
t.y=now[1];
t.step=0;
vis[t.x][t.y]=1;
queue<node>q;
q.push(t);
while(!q.empty())
{
t=q.front();
q.pop();
now[0]=t.x;
now[1]=t.y;
if(t.x==c||t.y==c)
{
ans1=t.x;
ans2=t.y;
return t.step;
}
/*将第一个倒满;*/
tt[0]=now[0];
tt[1]=now[1];
d.x=limt[0];
d.y=now[1];
d.step=t.step+1;
if(vis[d.x][d.y]==0)
{
vis[d.x][d.y]=1;
q.push(d);
pre[d.x][d.y].x=t.x;
pre[d.x][d.y].y=t.y;
pre[d.x][d.y].step=1;
}
now[0]=tt[0];
now[1]=tt[1];
/*将第二个倒满*/
tt[0]=now[0];
tt[1]=now[1];
d.x=now[0];
d.y=limt[1];
d.step=t.step+1;
if(vis[d.x][d.y]==0)
{
vis[d.x][d.y]=1;
q.push(d);
pre[d.x][d.y].x=t.x;
pre[d.x][d.y].y=t.y;
pre[d.x][d.y].step=2;
}
now[0]=tt[0];
now[1]=tt[1];
/*将第一个抽干*/
tt[0]=now[0];
tt[1]=now[1];
d.x=0;
d.y=now[1];
d.step=t.step+1;
if(vis[d.x][d.y]==0)
{
vis[d.x][d.y]=1;
q.push(d);
pre[d.x][d.y].x=t.x;
pre[d.x][d.y].y=t.y;
pre[d.x][d.y].step=3;
}
now[0]=tt[0];
now[1]=tt[1];
/*将第二个抽干*/
tt[0]=now[0];
tt[1]=now[1];
d.x=now[0];
d.y=0;
d.step=t.step+1;
if(vis[d.x][d.y]==0)
{
vis[d.x][d.y]=1;
q.push(d);
pre[d.x][d.y].x=t.x;
pre[d.x][d.y].y=t.y;
pre[d.x][d.y].step=4;
}
now[0]=tt[0];
now[1]=tt[1];
/*将第一个导入第二个*/
if(now[0]>0)
{
tt[0]=now[0];
tt[1]=now[1];
if(now[0]>=(limt[1]-now[1]))
{
now[0]=now[0]+now[1]-limt[1];
now[1]=limt[1];
}
else
{
now[1]+=now[0];
now[0]=0;
}
d.x=now[0];
d.y=now[1];
d.step=t.step+1;
if(vis[d.x][d.y]==0)
{
vis[d.x][d.y]=1;
q.push(d);
pre[d.x][d.y].x=t.x;
pre[d.x][d.y].y=t.y;
pre[d.x][d.y].step=5;
}
now[0]=tt[0];
now[1]=tt[1];
}
/*将第二个导入第一个*/
if(now[1]>0)
{
tt[0]=now[0];
tt[1]=now[1];
if(now[1]>=(limt[0]-now[0]))
{
now[1] -= limt[0]-now[0];
now[0] = limt[0];
}
else
{
now[0]+=now[1];
now[1]=0;
}
d.x = now[0];
d.y = now[1];
d.step = t.step + 1;
if ( vis[d.x][d.y]==0 ) {
vis[d.x][d.y] = 1;
q.push(d);
pre[d.x][d.y].x = t.x;
pre[d.x][d.y].y = t.y;
pre[d.x][d.y].step = 6;
}
now[0] = tt[0];
now[1] = tt[1];
}
}
return -1;
}
void pri( int x, int y ) // 对六种情况的编号
{
if ( x==0 && y==0 ) {
return ;
}
pri(pre[x][y].x,pre[x][y].y);
if ( pre[x][y].step==1 ) {
cout << "FILL(1)" << endl;
}
if ( pre[x][y].step==2 ) {
cout << "FILL(2)" << endl;
}
if ( pre[x][y].step==3 ) {
cout << "DROP(1)" << endl;
}
if ( pre[x][y].step==4 ) {
cout << "DROP(2)" << endl;
}
if ( pre[x][y].step==5 ) {
cout << "POUR(1,2)" << endl;
}
if ( pre[x][y].step==6 ) {
cout << "POUR(2,1)" << endl;
}
}
int main()
{
scanf("%d%d%d", &a,&b,&c);
limt[0]=a;
limt[1]=b;
now[1]=0;
now[0]=0;
memset(vis,0,sizeof(vis));
int k=bfs();
if(k==-1)
{
printf("impossible\n");
}
else
{
printf("%d\n", k);
pri(ans1,ans2);
}
}