链接:http://poj.org/problem?id=3414
思路:就是bfs,有六种操作,FILL 1或2,DROP 1或2 ,将1倒到2,将2倒到1。要注意的是要使用标记数组vis[i][j] 表示左边的杯子为i升,右边的杯子为j升,如果已被标记说明之前已经出现这种情况,就不要入队。从(0,0)开始bfs。
因为题目中需要输出如何倒,那么就需要保存路径。。以前似乎自己还没有写过,只是知道这种思想,用一个数组记录下当前位置的前一个位置的坐标。最后通过终点找回去,找出整条路径,将路上的每个点都保存到答案数组中,(这里我是逆着保存的,也就是终点保存在最后面),最后输出的时候顺着遍历一遍答案数组,比较前后两个的情况,输出操作。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
#define M 109
#define INF 0x3f3f3f3f
int vis[M][M];
int n,m,k;
int ans;
struct state
{
int x,y;
int step;
}cur,next1;
struct
{
int lx,ly;
}s[M][M]; //记录路径 保存上一个点坐标
struct
{
int a,b;
}ss[100009]; //保存答案的数组
void bfs(state temp)
{
queue<state> q;
temp.step = 0;
s[temp.x][temp.y].lx = 0;
s[temp.x][temp.y].ly = 0;
vis[temp.x][temp.y] = 0;
q.push(temp);
while(!q.empty())
{
cur = q.front();
vis[cur.x][cur.y] = 1;
q.pop();
if(cur.x==k || cur.y==k)
{
ans = cur.step;
printf("%d\n",ans);
int i = ans;
ss[i].a = cur.x;
ss[i--].b = cur.y;
int xx = s[cur.x][cur.y].lx;
int yy = s[cur.x][cur.y].ly;
while(i!=-1)
{
ss[i].a = xx; //从后往前保存答案。
ss[i--].b = yy;
int temp1 = xx;
int temp2 = yy;
xx = s[temp1][temp2].lx;
yy = s[temp1][temp2].ly;
}
return ;
}
next1.step = cur.step+1;
if(cur.y < m) //倒满y
{
next1.x = cur.x;
next1.y = m;
if(!vis[next1.x][next1.y])
{ //要有括号。。。不然没有加入队列也保存了路径。。。
q.push(next1);
s[next1.x][next1.y].lx = cur.x; //只有加入队列才保存路径
s[next1.x][next1.y].ly = cur.y;
}
}
if(cur.x < n) //倒满x
{
next1.x = n;
next1.y = cur.y;
if(!vis[next1.x][next1.y])
{
q.push(next1);
s[next1.x][next1.y].lx = cur.x;
s[next1.x][next1.y].ly = cur.y;
}
}
if(cur.x > 0)
{
next1.x = 0; //倒空x
next1.y = cur.y;
if(!vis[next1.x][next1.y])
{
q.push(next1);
s[next1.x][next1.y].lx = cur.x;
s[next1.x][next1.y].ly = cur.y;
}
if(cur.y < m) //x倒到y
{
if(cur.x > m-cur.y)
{
next1.x = cur.x-(m-cur.y);
next1.y = m;
}
else
{
next1.x = 0;
next1.y = cur.y+cur.x;
}
if(!vis[next1.x][next1.y])
{
q.push(next1);
s[next1.x][next1.y].lx = cur.x;
s[next1.x][next1.y].ly = cur.y;
}
}
}
if(cur.y > 0)
{
next1.x = cur.x; //倒空y
next1.y = 0;
if(!vis[next1.x][next1.y])
{
q.push(next1);
s[next1.x][next1.y].lx = cur.x;
s[next1.x][next1.y].ly = cur.y;
}
if(cur.x < n)//y倒到x
{
if(cur.y > n-cur.x)
{
next1.x = n;
next1.y = cur.y-(n-cur.x);
}
else
{
next1.x = cur.x+cur.y;
next1.y = 0;
}
if(!vis[next1.x][next1.y])
{
q.push(next1);
s[next1.x][next1.y].lx = cur.x;
s[next1.x][next1.y].ly = cur.y;
}
}
}
}
}
int main()
{
while(scanf("%d %d %d",&n,&m,&k)==3)
{
memset(vis,0,sizeof(vis));
memset(ss,0,sizeof(ss));
memset(s,0,sizeof(s));
ans = INF;
cur.x = 0;
cur.y = 0;
bfs(cur);
if(ans==INF)
printf("impossible\n");
else
{
//ss[0].a = 0;
//ss[0].b = 0;
for(int i = 0;i < ans;i++)
{
int x1 = ss[i].a;
int y1 = ss[i].b;
int x2 = ss[i+1].a;
int y2 = ss[i+1].b;
if(x1==0 && x2==n && y1==y2) printf("FILL(1)\n"); //要写清楚情况 fill的时候必须y是不变的。。
if(y1==0 && y2==m && x1==x2) printf("FILL(2)\n");
if(x1>0 && x2==0 && y1==y2) printf("DROP(1)\n");
if(x2>0 && y2==0 && x1==x2) printf("DROP(2)\n");
if(y2>y1 && x2<x1) printf("POUR(1,2)\n");
if(x2>x1 && y2<y1) printf("POUR(2,1)\n");
}
}
}
return 0;
}