OpenJudge-2152:Pots

2152:Pots


描述
You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:

    FILL(i)        fill the pot i (1 ≤ i ≤ 2) from the tap;
    DROP(i)      empty the pot i to the drain;
    POUR(i,j)    pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).

Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.

输入
On the first and only line are the numbers A, B, and C. These are all integers in the range from 1 to 100 and C≤max(A,B).
输出
The first line of the output must contain the length of the sequence of operations K. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.

样例输入

3 5 4

样例输出

6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

题目解析
又是一道英文题,看着不爽哈…于是今天把它做出来了。经过翻译软件令人震惊的翻译(翻译成啥鬼样儿),作者终于理解这道题了。题目意思大概是这样:

有2个罐子编号为“1”和“2”。输入给定它们的容量A、B(前两个整数)以及要求得到的数量C(最后一个整数)。现在可以进行3种操作:FILL(i)- 把罐子i装满,DROP(i)- 把罐子i倒空,POUR(i,j)- 把罐子i的水倒入罐子j,直到罐子i中没有水或者罐子j被倒满了。通过多次操作得到目的-在任意一个罐子中的水为C。输出最少的操作数,并同时输出操作过程。

我们可以看到这道题的每一个操作互相都没有联系性,所以我们可以给他们编一个号。这里要注意如何编号——虽然题目说的是有3种规则,但实际上有6种,即2个罐子分别3个规则。以下是作者的编号:

1:FILL(1);2:FILL(2);3:DROP(1);4:DROP(2);5:POUR(1,2);6:POUR(2,1)

然后就开始广度优先搜索了(深度优先搜索会TLE)。起始的元素也就是2个罐子都为空。为了更加方便,我们设置一个结构体,元素表如下(均为int):

a-当前罐子1的储水量;b-当前罐子2的储水量;father-到达这个位置的上一个位置在数组中的下标;set-此次操作的编号

由于我们在搜索完后还要重新访问之前的元素,我们就不再使用C++STL的queue FIFO队列了。
广度优先搜索里我们需要枚举6种情况,可以使用switch。注意POUR操作时的两种情况!!然后就要判断是否得到最终答案,若是,则利用之前结构体中的father变量倒推回起点。最后记得逆序输出答案!若不是,则存入数组。


题外话
深度优先搜索并不是万能的,大家可以按照下列规则来选择搜索方法:

求最短用广度优先搜索;答“是否”用深度优先搜索


程序样例(这才是重点)

/*Lucky_Glass*/
#include<cstdio>
#include<vector>
using namespace std;
struct SET
{//set: 1.FILL(a) 2.FILL(b) 3.DROP(a) 4.DROP(b) 5.POUR(a,b) 6.POUR(b,a)
    int a,b,father,set;
}OT[10000005],OTing;//operation(操作)
bool repeat[105][105]; //判断重复数组
int main()
{
    int A,B,C,f=0,l=1;
    scanf("%d%d%d",&A,&B,&C);
    OT[0].a=0;OT[0].b=0;OT[0].father=-1;OT[0].set=-1;
    repeat[0][0]=true; //初始化
    while(f<l)
    {
        for(int i=1;i<=6;i++) //枚举
        {
            OTing=OT[f];
            OTing.set=i;OTing.father=f;
            switch(OTing.set) //操作
            {
                case 1: //FILL(1)
                    OTing.a=A; //装满
                    break;
                case 2: //FILL(2)
                    OTing.b=B; //装满
                    break;
                case 3: //DROP(1)
                    OTing.a=0; //倒空
                    break;
                case 4: //DROP(2)
                    OTing.b=0; //倒空
                    break;
                case 5: //POUR(1,2)
                    if(OTing.b+OTing.a<=B) //1倒空
                        OTing.b+=OTing.a,OTing.a=0;
                    else //2倒满
                        OTing.a=OTing.a-(B-OTing.b),OTing.b=B;
                    break;
                case 6:
                    if(OTing.a+OTing.b<=A) //2倒空
                        OTing.a+=OTing.b,OTing.b=0;
                    else //1倒满
                        OTing.b=OTing.b-(A-OTing.a),OTing.a=A;
                    break;
            }
            if(repeat[OTing.a][OTing.b]) continue; //重复
            repeat[OTing.a][OTing.b]=true;
            OT[l++]=OTing;
            if(OTing.a==C || OTing.b==C) //完成
            {
                vector<int> ans; //存入答案
                int G=l-1;
                while(true)
                {
                    ans.push_back(OT[G].set);
                    G=OT[G].father;
                    if(G==-1) break;
                }
                int size=ans.size()-1;
                printf("%d\n",size);
                for(int i=size-1;i>=0;i--)
                    switch(ans[i])
                    {
                        case 1: printf("FILL(1)\n");break;
                        case 2: printf("FILL(2)\n");break;
                        case 3: printf("DROP(1)\n");break;
                        case 4: printf("DROP(2)\n");break;
                        case 5: printf("POUR(1,2)\n");break;
                        case 6: printf("POUR(2,1)\n");break;
                    }
                return 0;
            }
        }
        f++;
    }
    printf("impossible\n");
    return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值