【POJ 3414】Pots(BFS)

该博客介绍了如何利用BFS(广度优先搜索)算法解决POJ 3414题目,即在给定两个不同容量的水壶中找到最短操作序列来得到特定体积的水。博主分析了题意,提供了操作类型,并展示了通过编程实现寻找最少操作次数的思路和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pots

Description
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)


题意:

输入数据:A,B,C。A表示容器a容量,B表示容器b容量,C为将要做的事:使任意一个容器装有C容量的水(C<=max(A,B))
你能做三种操作:
1.FILL(i) :将容器i(序号,i=1或2即A和B)用水装满
2.DROP(i):将容器i(序号)里的水倒光
3.POUR(i,j):将容器i里的水倒入j(序号)中。有两种可能性:如果两容器水量之和小于容器j(序号)容量,则容器i里的水被倒光;如果如果两容器水量之和大于容器j(序号)容量,则容器j里装满水。
输出最少操作次数和每次的操作


思路:

哎呀,这题有种似曾相识的感觉。经分析得这题也是有六次操作,和HDU 1495-非常可乐很类似嘛。稍微麻烦点的就是要输出一对操作字符串。既然是字符串的话,结构体里加一个str变量,然后每次strcpy就可以了。思路很类似,详细见注释。


代码示例:
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define MAX 105
using namespace std;
int A,B,C;
bool vis[MAX][MAX];
struct point {
    int vol_a;//容器a 
    int vol_b;//容器b 
    int step;//次数统计 
    char str[MAX][MAX];//字符串拷贝 
};

queue<point> que;

bool bfs()
{
    //初始化 
    point p,q;
    memset(vis,false,sizeof(vis));
    p.vol_a=0,p.vol_b=0,p.step=0;
    vis[0][0]=true;
    while(!que.empty()) que.pop();
    //开始将结点压入队列 
    que.push(p);
    while(!que.empty())
    {
        p=que.front();
        que.pop();
        //判断出口并输出 
        if(p.vol_a==C||p.vol_b==C)
        {
            cout<<p.step<<endl;
            for(int i=1;i<=p.step;i++)
                cout<<p.str[i]<<endl;
            return true;
        } 
        //把a倒满 
        if(p.vol_a==0)
        {
            q=p;
            q.vol_a=A;
            q.step++;
            strcpy(q.str[q.step],"FILL(1)");
            if(!vis[q.vol_a][q.vol_b]){
                vis[q.vol_a][q.vol_b]=true;
                que.push(q);
            } 
        }
        //把a中水倒出 
        else if(p.vol_a<=A)
        {
            q=p;
            q.vol_a=0;
            q.step++;
            strcpy(q.str[q.step],"DROP(1)");
            if(!vis[q.vol_a][q.vol_b])
            {
                vis[q.vol_a][q.vol_b]=true;
                que.push(q);
            }
            //a->b
            if(q.vol_b<B)  //如果b没装满 ,才能往b内装 
            {
                q=p;
                if(q.vol_a+q.vol_b<=B)  //如果 总量都不足以装满b容量 
                {
                    q.vol_b=q.vol_a+q.vol_b;  
                    q.vol_a=0;
                }
                else  //如果 总量超过了b容量 
                {
                    q.vol_a=q.vol_a+q.vol_b-B;  //两句顺序不能反!! 
                    q.vol_b=B;
                }
                q.step++; //步数统计 
                strcpy(q.str[q.step],"POUR(1,2)"); //字符串赋给q.str[步数(即可认为是“层次”,bfs每一层都会遍历所有)] 
                if(!vis[q.vol_a][q.vol_b])
                {
                    vis[q.vol_a][q.vol_b]=true;
                    que.push(q);
                }
            }
        }
        //把b倒满 (不分别解释,与上相对应) 
        if(p.vol_b==0)
        {
            q=p;
            q.vol_b=B;
            q.step++;
            strcpy(q.str[q.step],"FILL(2)");
            if(!vis[q.vol_a][q.vol_b])
            {
                vis[q.vol_a][q.vol_b]=true;
                que.push(q);
            } 
        }
        //把b中水倒出 
        else if(p.vol_b<=B)
        {
            q=p;
            q.vol_b=0;
            q.step++;
            strcpy(q.str[q.step],"DROP(2)");
            if(!vis[q.vol_a][q.vol_b])
            {
                vis[q.vol_a][q.vol_b]=true;
                que.push(q);
            }
            //b->a
            if(q.vol_a<A)
            {
                q=p;
                if(q.vol_a+q.vol_b<=A)
                {
                    q.vol_a=q.vol_a+q.vol_b;
                    q.vol_b=0;
                }
                else 
                {
                    q.vol_b=q.vol_a+q.vol_b-A;
                    q.vol_a=A;

                }
                q.step++;
                strcpy(q.str[q.step],"POUR(2,1)");
                if(!vis[q.vol_a][q.vol_b])
                {
                    vis[q.vol_a][q.vol_b]=true;
                    que.push(q);
                }
            }
        }
    }
    return false;
}

int main()
{
    while(cin>>A>>B>>C&&A&&B&&C)
    {
         bool flag=bfs();
         if(flag==false) cout<<"impossible"<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值