POJ - 3414 Pots

这道题的题意是给你两个容器,问你通过容器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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值