poj3414——Pots

题目大意:有两个水壶容量分别为A、B,有三种操作,FILL(i):将第i个水壶用水龙头装满水;DROP(i):将第i个水壶的水倒入下水道;POUR(i,j):将第i个水壶中的水倒入第j个水壶(pour后要么j已经满了,要么i已经空了),问如何操作能让其中一个水壶恰好装有C升的水,并让操作数最少

输入:A B C(C≤max(A,B)

输出:如果无解输出impossible

           如果有解输出如下

           操作步骤数

           第i步操作

分析:又是一道bfs求最短路径,bfs搜索六个子树分别对应六种操作(本题中用数字代表)——FILL(1),FILL(2),DROP(1),DROP(2),POUR(1,2),POUR(2,1),记录每步操作的父节点,以此来找出最终解这条路上的所有操作,从根节点开始依次输出,如果队列都空了还没找到解,则输出impossible

           status结构体记录每次两个容器中的水量及此时的状态,id[i]数组记录第i步操作在队列中的编号

代码:

#include<stdio.h>
#include<string.h>


const int maxn = 110;
int vis[maxn][maxn]; //标记状态是否入队过
int a,b,c; //容器大小
int step; //最终的步数
int flag; //纪录是否能够成功


/* 状态纪录 */
struct Status{
    int k1,k2; //当前水的状态
    int op; //当前操作
    int step; //纪录步数
    int pre; //纪录前一步的下标
}q[maxn*maxn];
int id[maxn*maxn]; //纪录最终操作在队列中的编号
int lastIndex; //最后一个的编号


void bfs()
{
    Status now, next;


    int head, tail;
    head = tail = 0;


    q[tail].k1 = 0; q[tail].k2 = 0;
    q[tail].op = 0; q[tail].step = 0; q[tail].pre = 0;


    tail++;


    memset(vis,0,sizeof(vis));
    vis[0][0] = 1; //标记初始状态已入队


    while(head < tail) //当队列非空
    {
        now = q[head]; //取出队首
        head++; //弹出队首


        if(now.k1 == c || now.k2 == c) //应该不会存在这样的情况, c=0
        {
            flag = 1;
            step = now.step;
            lastIndex = head-1; //纪录最后一步的编号
            return;
        }


        for(int i = 1; i <= 6; i++) //分别遍历 6 种情况
        {
            if(i == 1) //fill(1)
            {
                next.k1 = a;
                next.k2 = now.k2;
            }
            else if(i == 2) //fill(2)
            {
                next.k1 = now.k1;
                next.k2 = b;
            }
            else if(i == 3) //drop(1)
            {
                next.k1 = 0;
                next.k2 = now.k2;
            }
            else if(i == 4) // drop(2);
            {
                next.k1 = now.k1;
                next.k2 = 0;
            }
            else if(i == 5) //pour(1,2)
            {
                if(now.k1+now.k2 <= b) //如果不能够装满 b
                {
                    next.k1 = 0;
                    next.k2 = now.k1+now.k2;
                }
                else //如果能够装满 b
                {
                    next.k1 = now.k1+now.k2-b;
                    next.k2 = b;
                }
            }
            else if(i == 6) // pour(2,1)
            {
                if(now.k1+now.k2 <= a) //如果不能够装满 a
                {
                    next.k1 = now.k1+now.k2;
                    next.k2 = 0;
                }
                else //如果能够装满 b
                {
                    next.k1 = a;
                    next.k2 = now.k1+now.k2-a;
                }
            }


            next.op = i; //纪录操作
            if(!vis[next.k1][next.k2]) //如果当前状态没有入队过
            {
                vis[next.k1][next.k2] = 1; //标记当前状态入队
                next.step = now.step+1; //步数 +1
                next.pre = head-1; //纪录前一步的编号


                //q.push(next);
                //q[tail] = next; 加入队尾
                q[tail].k1 = next.k1; q[tail].k2 = next.k2;
                q[tail].op = next.op; q[tail].step = next.step; q[tail].pre = next.pre;
                tail++; //队尾延长
            }
        }
    }




}


int main()
{
    while(scanf("%d%d%d", &a,&b,&c) != EOF)
    {
        flag = 0; //初始化不能成功
        step = 0;


        bfs();
        if(flag)
        {
            printf("%d\n", step);


            id[step] = lastIndex; //最后一步在模拟数组中的编号
            for(int i = step-1; i >= 1; i--)
            {
                id[i] = q[id[i+1]].pre; //向前找前一步骤在模拟数组中的编号
            }


            for(int i = 1; i <= step; i++)
            {
                if(q[id[i]].op == 1)
                    printf("FILL(1)\n");


                else if(q[id[i]].op == 2)
                    printf("FILL(2)\n");


                else if(q[id[i]].op == 3)
                    printf("DROP(1)\n");


                else if(q[id[i]].op == 4)
                    printf("DROP(2)\n");


                else if(q[id[i]].op == 5)
                    printf("POUR(1,2)\n");


                else if(q[id[i]].op == 6)
                    printf("POUR(2,1)\n");
            }
        }
        else printf("impossible\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值