这道题的题意是给你两个容器,问你通过容器A和容器B能获得容量为C的液体。其中操作有三种,fill(a):把a填满,drop(a):把a倒掉,pour(a,b):把a倒入b中。要求把操作顺序输出。
有很多种操作方式,我们一种一种遍历,直到出现结果为止,可以采取bfs的方式,这道题的难点在于怎么把路径输出。在bfs中,我们开始会选区队首的元素,通过队首的元素来获得队尾的元素,所以我们只需要在队尾标记队首就行,如果可行,我们顺着标记可以得到结果。代码如下:
#include <map>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 105;
int a, b, c, t;
int le, ri; //队首, 队尾
int v[N][N]; //判断这种情况是否出现过
int x[N * N], p[N * N], op[N * N], d[N * N]; //操作主体(A,B), 连接上个结点,操作类型(fill,drop,pour),操作次数
pair<int, int> q[N * N];
void check(int i, int j, int o, int k)
{
if(v[i][j]) return;
v[i][j] = 1;
p[ri] = le;
op[ri] = o;
x[ri] = k;
d[ri] = d[le] + 1;
q[ri++] = make_pair(i, j);
}
int bfs()
{
int ca, cb = le = ri = 0;
q[ri++] = make_pair(0, 0);
memset(v, 0, sizeof(v)), v[0][0] = 1;
while(le < ri)
{
ca = q[le].first, cb = q[le].second;
if(ca == c || cb == c) return le;
check(a, cb, 1, 1); //FILL(1);
check(ca, b, 1, 2); //FILL(2);
check(0, cb, 2, 1); //DROP(1);
check(ca, 0, 2, 2); //DROP(2);
if(ca > b - cb)
check(ca - b + cb, b, 3, 1);
else
check(0, ca + cb, 3, 1); //POUR(1,2);
if(cb > a - ca)
check(a, cb - a + ca, 3, 2);
else
check(ca + cb, 0, 3, 2); //POUR(2,1);
++le;
}
return 0;
}
void print(int k)
{
if(p[k] > 0)
print(p[k]);
if(op[k] == 1)
printf("FILL(%d)\n", x[k]);
if(op[k] == 2)
printf("DROP(%d)\n", x[k]);
if(op[k] == 3)
printf("POUR(%d,%d)\n", x[k], 3 - x[k]);
}
int main()
{
int ans;
while(~scanf("%d%d%d", &a, &b, &c)) {
if(ans = bfs()) {
printf("%d\n",d[ans]);
print(ans);
}
else puts("impossible");
}
return 0;
}