POJ-1606 Jugs

#include <iostream>
#include <string>
#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;

int CA, CB, n;              //A桶 B桶容量 n目标容量
char STEP[7][10] = {"success", "fill A", "fill B", "empty A", "empty B", "pour A B", "pour B A"};   //最后输出的步骤
int sign[1001][1001];       //标记已访问过的ca cb(用next.ca 做横坐标 用next.cb 做纵坐标)
struct Step                 //构建结构体
{
    int ca;                 //当前存放的A桶的量
    int cb;                 //当前存放的B桶的量
    int step;               //标记这是第几步的操作(为后面输出做准备)
    int process[10000];     //存放当前步骤的序号(上面STEP数组其实已经按着顺序写了)例如第一个操作是 empty A.则 process[0] = 3.
}start;                     //用于存放初始状态
queue<Step> water;          //存放Step的队列

inline void fill_A(Step &temp)      //函数1:将A装满
{
    temp.ca = CA;
    temp.process[temp.step] = 1;    //当前步骤的操作序号存入。
    temp.step ++;                   //step++为下一次的存入操作序号做准备
}

inline void fill_B(Step &temp)      //函数2:将B装满
{
    temp.cb = CB;
    temp.process[temp.step] = 2;
    temp.step ++;
}

inline void empty_A(Step &temp)     //函数3: 将A清空
{
    temp.ca = 0;
    temp.process[temp.step] = 3;
    temp.step ++;
}

inline void empty_B(Step &temp)     //函数4: 将B清空
{
    temp.cb = 0;
    temp.process[temp.step] = 4;
    temp.step ++;
}

inline void pour_A_B(Step &temp)    //函数5: 将A倒入B
{
    if(temp.ca + temp.cb > CB)      //如果A倒入B超过B的容量
    {
        temp.ca -= CB - temp.cb;    //A只倒入部分(将B装满的量)
        temp.cb = CB;               //B装满
    }
    else                            //如果没满出 则将A全倒入B
    {
        temp.cb += temp.ca;
        temp.ca = 0;
    }
    temp.process[temp.step] = 5;
    temp.step ++;
}

inline void pour_B_A(Step &temp)    //函数6: 将B倒入A
{
    if(temp.ca + temp.cb > CA)      //同理函数5
    {
        temp.cb -= CA - temp.ca;
        temp.ca = CA;
    }
    else
    {
        temp.ca += temp.cb;
        temp.cb = 0;
    }
    temp.process[temp.step] = 6;
    temp.step ++;
}

void bfs()                          //bfs宽度搜索
{
    while(!water.empty())           //队列清空
        water.pop();
    water.push(start);
    sign[start.ca][start.cb] = 1;   //标记初始位置已访问
    while(!water.empty())           //如果队列不空 继续循环
    {
        Step now = water.front();   //保存队列的第一个元素
        water.pop();                //扔掉当前第一个元素 为下一个元素成第一个元素做准备
        for(int i = 1; i <= 6; i ++)//六种操作 按序号分别操作
        {
            Step next = now;        //next存储下一个元素
            if(i == 1 && next.ca < CA)                          //优化:如果next.ca(A桶)本来就是满的 再进行fill没有意义 跳过
                fill_A(next);
            else if(i == 2 && next.cb < CB)                     //优化:如果next.cb(B桶)本来就是满的 再进行fill没有意义 跳过
                fill_B(next);
            else if(i == 3 && next.ca != 0)                     //优化:如果next.ca(A桶)本来就是空的 再进行empty没有意义 跳过
                empty_A(next);
            else if(i == 4 && next.cb != 0)                     //优化:如果next.cb(B桶)本来就是空的 再进行empty没有意义 跳过
                empty_B(next);
            else if(i == 5 && next.ca != 0 && next.cb != CB)    //优化:如果next.ca(A桶)空的 或者 next.cb(B桶)满的 再pour没有意义 跳过
                pour_A_B(next);
            else if(i == 6 && next.cb != 0 && next.ca != CA)    //优化:如果next.cb(B桶)空的 或者 next.ca(A桶)满的 再pour没有意义 跳过
                pour_B_A(next);
            if(sign[next.ca][next.cb])                          //如果此状态标记为1 说明被访问过 直接跳过 其实也就防止出现相同状态(即先前已经到达过 没必要前进后又绕回来这个状态)
                continue;
            if(next.ca == n || next.cb == n)                    //如果A桶 或者 B桶 达到目标容量 输出 跳出结束
            {
                for(int j = 0; j < next.step; j ++)             //step的作用体现
                     printf("%s\n", STEP[next.process[j]]);     //next.process[j]储存的是操作序号 之后按STEP[x]字符数组的顺序查找输出操作
                return;
            }
            else
            {
                water.push(next);                               //存入队列(在之前的优化 可以省去很多没必要的重复操作 队列里面的元素少 让时间优 否则超时)
                sign[next.ca][next.cb] = 1;                     //标记已访问
            }

        }
    }
}

int main()
{
    while(~scanf("%d %d %d", & CA, & CB, & n))                  //输入(个人感言:就是这里脑残...)
    {
        start.ca = 0;                                           //初始化A桶
        start.cb = 0;                                           //初始化B桶
        start.step = 0;                                         //初始化步骤数
        memset(start.process, 0, sizeof(start.process));        //初始化步骤序号数组
        memset(sign, 0, sizeof(sign));                          //初始化标记数组
        bfs();
        printf("%s\n", STEP[0]);                                //输出成功
    }
    return 0;                                                   //做人嘛 开心就好
}

 

题意:给2桶水。一桶A 一桶B 。AB桶都有最大容量。A的容量小于B容量。之后输入CA CB N 三个数。CA CB分别代表A桶 B桶的容量。N代表目标容量(小于等于B桶)。输出A桶或者B桶装到了目标容量的步骤。总共有六种步骤。1.将A桶装满(fill A)2.将B桶装满(fill B)3.清空A桶(empty A)4.清空B桶(empty B)5.将A倒入B(如果B满了则停止倒入 A中有剩余)(pour A B)6.将B倒入A(如果A满了则停止倒入 B中有剩余)(pour B A)

题解:第一次比较完美的写出了bfs。一气呵成吧。输入小数据都是对的。不过大数据就超时。为此得剪枝。我一开始很纳闷该怎么剪。后来还是想到了标记数组。还有就是每一步的剪枝。最后完成了上面那种完全体...总耗时一个下午...(最后居然还因为while(sanf)没写成while(~scanf)超时 醉人...检查出来也是哭笑不得..)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值