POJ-1606 Jugs

来源:互联网 发布:中仕网络 编辑:程序博客网 时间:2024/05/18 03:33
#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