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.

Input
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).

Output
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’.

Sample Input
3 5 4
Sample Output
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)`

题意大概就是给你两个杯子,有无限多的水,问可不可以经过最少的操作倒出来所需要的水的容量,下面有3种操作
FILL(A):把A杯子装满水
POUR(A,B):把A杯子里的水倒进B杯子,当然水不能溢出,也就是说,如果A杯子容量有5L,B杯子容量有3L,假设现在B杯是空的,A杯是装满水的,执行一个POUR(A,B)操作后,那么现在B杯就装满了3L水,A杯就剩2L
DROP(A):这个意思就是把A杯子里的水倒掉

输入:A,B,C
第一个数代表A杯的容量,第二个数代表B杯的容量,第三个数代表要得到的水的容量
输出:
要是可以通过这3种操作,可以得到所要水的容量,先打印一个数字,代表要经过多少种操作,然后打印经过的步骤。
要是得不到所要水的容量,就输出impossible

现在来看看这道题,要求经过最少的步骤,我们马上可以想到宽搜,而且还要输出操作的步骤,所以我们可以来一个结构体,来保存当前A杯子里水的容量和B杯子里水的容量,还有已经走过的操作,当前这是第几个步骤

typedef struct {
    int m;//当前这是第几步
    int la;//A杯容量
    int lb;//B杯容量
    string s;//走过的操作
}Node;

然后就是把这个结构体放到队列里边,让它进行宽搜。
每次当前这种情况都可以进行6种操作:
1.FILL(1)
2.FILL(2)
3.POUR(1,2)//需要注意的地方
4.POUR(2,1)//需要注意的地方
5.DROP(1)
6.DROP(2)
每次进行完一种操作,都把这种情况进行标记,要是这种情况已经出现过,就不要让它进入队列,(小编当时就没有进行标记,结果电脑炸了好多次)要是这种情况没有出现过,那就判断A杯或者B杯是否达到想要的容量,要是达到了想要的容量,就可以进行输出啦!下面看看输出的代码

if(next.la==K||next.lb==K){
        printf("%d\n",next.m);//输出多少种操作
        for(int j=0;j<next.s.size();j++){
            F=1;//标记可以找到所要的容量
            printf("%c",next.s[j]);
            if(next.s[j]==')') printf("\n");//每遇到一个右括号,就进行一次换行
        }
        return 0;
}

下面看看这6种操作的代码:

for(int i=0;i<6;i++){
    if(i==0){
        next.la=curr.la;
        next.lb=B;
        next.s=curr.s+"FILL(2)";
    }
    if(i==1){
        next.la=A;
        next.lb=curr.lb;
        next.s=curr.s+"FILL(1)";
    }
    if(i==2){//将第二个杯子里的水倒入第一个杯子
        if(curr.la+curr.lb<=A)/*如果两个杯子里的水加起来小于
        第一个杯子的容量,那么第一个杯子里水的容量就等于两杯子里水的容量之和*/
            next.la=curr.la+curr.lb;
        else
            next.la=A;/*否则的话第一个杯子里水的容量就等于第一个杯子的容量*/
        next.lb=curr.lb-next.la+curr.la;/*第二个杯子里水的容量就等于前
        一次两杯子里水的容量之和减去下一次第一个杯子里水的容量*/
        next.s=curr.s+"POUR(2,1)";
    }
    if(i==3){
        if(curr.la+curr.lb<=B)
            next.lb=curr.la+curr.lb;
        else
            next.lb=B;
        next.la=curr.la-next.lb+curr.lb;
        next.s=curr.s+"POUR(1,2)";
    }
    if(i==4){
        next.la=0;
        next.lb=curr.lb;
        next.s=curr.s+"DROP(1)";
    }
    if(i==5){
        next.la=curr.la;
        next.lb=0;
        next.s=curr.s+"DROP(2)";
    }

下面瞧瞧AC代码

//倒水问题 
#include<string>
#include<cstring> 
#include<queue>
#include<cstdio>
using namespace std;
typedef struct {
    int m;
    int la;
    int lb;
    string s;
}Node;
queue<Node> R;
int main(){
    int F=0;
    int a[105][105];
    memset(a,0,sizeof(a));
    Node curr,next;
    int A,B,K;
    scanf("%d%d%d",&A,&B,&K);
    if(K==A&&K!=B){
        printf("1\n");
        printf("FILL(1)");
    }
    else if(K==B&&K!=A){
        printf("1\n");
        printf("FILL(2)");
    }
    else{
            curr.la=0;
            curr.lb=0;
            curr.s="";
            curr.m=0;
            R.push(curr);
            while(!R.empty()){
                curr=R.front();
                R.pop();
                next.m=curr.m+1;
                for(int i=0;i<6;i++){
                    if(i==0){
                        next.la=curr.la;
                        next.lb=B;
                        next.s=curr.s+"FILL(2)";
                    }
                    if(i==1){
                        next.la=A;
                        next.lb=curr.lb;
                        next.s=curr.s+"FILL(1)";
                    }
                    if(i==2){
                        if(curr.la+curr.lb<=A)
                            next.la=curr.la+curr.lb;
                        else
                            next.la=A;
                            next.lb=curr.lb-next.la+curr.la;
                            next.s=curr.s+"POUR(2,1)";
                    }
                    if(i==3){
                        if(curr.la+curr.lb<=B)
                            next.lb=curr.la+curr.lb;
                        else
                            next.lb=B;
                            next.la=curr.la-next.lb+curr.lb;
                            next.s=curr.s+"POUR(1,2)";
                    }
                    if(i==4){
                        next.la=0;
                        next.lb=curr.lb;
                        next.s=curr.s+"DROP(1)";
                    }
                    if(i==5){
                        next.la=curr.la;
                        next.lb=0;
                        next.s=curr.s+"DROP(2)";
                    }
                    if(!a[next.la][next.lb]){
                        if(next.la==K||next.lb==K){
                            printf("%d\n",next.m);
                            for(int j=0;j<next.s.size();j++){
                                F=1;
                                printf("%c",next.s[j]);
                                if(next.s[j]==')') printf("\n");
                            }
                            return 0;
                        }
                        R.push(next);
                        a[next.la][next.lb]=1;//标记这种情况
                    }
                }
            }
            if(F==0)
            printf("impossible\n");
    }
    return 0;
}

当时做这道题的时候WA了许多次,具体需要注意的就是要标记,还有POUR(A,B)这种操作,考虑到这些还是很容易做出来的,要是还是看不懂的话,可以联系小编。

猜你喜欢

转载自blog.csdn.net/ABC__xiaoming/article/details/81452274