《算法笔记》8.2小节——搜索专题->广度优先搜索(BFS)问题 E: 【宽搜入门】巧妙取量

【题目描述】
  有三个容器,容量分别为 a,b,c(a> b > c ),一开始a装满油,现在问是否只靠abc三个容器量出k升油。如果能就输出“yes”,并且说明最少倒几次,否则输出“no”。例如:10升油在10升的容器中,另有两个7升和3升的空容器,要求用这三个容器倒油,使得最后在abc三个容器中有一个刚好存有5升油,问最少的倒油次数是多少?(每次倒油,A容器倒到B容器,或者A内的油倒完,或者B容器倒满。
 10 7 3
(10 0 0)
(3 7 0):第一次
(3 4 3):第二次
(6 4 0):第三次
(6 1 3):第四次
(9 1 0):第五次
(9 0 1):第六次
(2 7 1):第七次
(2 5 3):第八次,出现5了。

Input

【输入格式】
  有多组测试数据。
  输入a,b,c, k四个正整数( 100 ≥ a > b > c≥1 , 1≤k< 100 )

Output

【输出格式】
  如果能得到k就输出两行。
  第一行“yes”,第二行为最少的次数
  否则输出“no”

Sample Input

10 7 3 5

Sample Output

yes
8

分析:这道题的做法和这节的问题A下面提示的有一些区别,这道题能做的操作只有把油从容器X倒到容器Y中,不可以从外面补充,也不可以把油直接倒掉。因此总共只有6种可能的操作:把油从a倒进b;把油从a倒进c;把油从b倒进c;把油从b倒进a;把油从c倒进b;把油从c倒进a.

搞清楚这点之后,用BFS就可以做了。

#include    <algorithm>
#include     <iostream>
#include      <cstdlib>
#include      <cstring>
#include       <string>
#include       <vector>
#include       <cstdio>
#include        <queue>
#include        <stack>
#include        <ctime>
#include        <cmath>
#include          <map>
#include          <set>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define db1(x) cout<<#x<<"="<<(x)<<endl
#define db2(x,y) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<endl
#define db3(x,y,z) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<endl
#define db4(x,y,z,a) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<", "<<#a<<"="<<(a)<<endl
#define db5(x,y,z,a,r) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<", "<<#a<<"="<<(a)<<", "<<#r<<"="<<(r)<<endl
using namespace std;
 
typedef struct node
{
    int cap_a,cap_b,cap_c,cnt_a,cnt_b,cnt_c,index;
}node;
 
node pour_a2b(node now,int a,int b)
{
    node temp=now;
    if(a==1&&b==2)
    {
        if(temp.cnt_a<temp.cap_b-temp.cnt_b)temp.cnt_b+=temp.cnt_a,temp.cnt_a=0;
        else temp.cnt_a-=temp.cap_b-temp.cnt_b,temp.cnt_b=temp.cap_b;
    }
    else if(a==2&&b==3)
    {
        if(temp.cnt_b<temp.cap_c-temp.cnt_c)temp.cnt_c+=temp.cnt_b,temp.cnt_b=0;
        else temp.cnt_b-=temp.cap_c-temp.cnt_c,temp.cnt_c=temp.cap_c;
    }
    else if(a==1&&b==3)
    {
        if(temp.cnt_a<temp.cap_c-temp.cnt_c)temp.cnt_c+=temp.cnt_a,temp.cnt_a=0;
        else temp.cnt_a-=temp.cap_c-temp.cnt_c,temp.cnt_c=temp.cap_c;
    }
    temp.index=now.index+1;
    return temp;
}
 
node pour_b2a(node now,int a,int b)
{
    node temp=now;
    if(a==2&&b==1)
    {
        if(temp.cnt_b<temp.cap_a-temp.cnt_a)temp.cnt_a+=temp.cnt_b,temp.cnt_b=0;
        else temp.cnt_b-=temp.cap_a-temp.cnt_a,temp.cnt_a=temp.cap_a;
    }
    else if(a==3&&b==2)
    {
        if(temp.cnt_c<temp.cap_b-temp.cnt_b)temp.cnt_b+=temp.cnt_c,temp.cnt_c=0;
        else temp.cnt_c-=temp.cap_b-temp.cnt_b,temp.cnt_b=temp.cap_b;
    }
    else if(a==3&&b==1)
    {
        if(temp.cnt_c<temp.cap_a-temp.cnt_a)temp.cnt_a+=temp.cnt_c,temp.cnt_c=0;
        else temp.cnt_c-=temp.cap_a-temp.cnt_a,temp.cnt_a=temp.cap_a;
    }
    temp.index=now.index+1;
    return temp;
}
 
int main(void)
{
    #ifdef test
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    clock_t start=clock();
    #endif //test
 
    node beg;
    int tar;
    while(~scanf("%d%d%d%d",&beg.cap_a,&beg.cap_b,&beg.cap_c,&tar))
    {
        int f=0;
        bool flag[101][101][101];
        memset(flag,0,sizeof(flag));
        if(max(beg.cap_a,max(beg.cap_b,beg.cap_c))<tar)printf("no\n");
        else
        {
            beg.cnt_a=beg.cap_a;beg.index=0;
 
            queue<node>que;que.push(beg);
            flag[beg.cnt_a][beg.cnt_b][beg.cnt_c]=1;
 
            while(!que.empty())
            {
                node fir=que.front(),temp=fir;que.pop();
                if(temp.cnt_a==tar||temp.cnt_b==tar||temp.cnt_c==tar)
                {
                    f=1;
                    printf("yes\n%d\n",temp.index);
                    break;
                }
 
                for(int i=1;i<=3;++i)
                {
                    if(i<=2)
                    {
                        temp=pour_a2b(fir,i,i+1);
                        if(flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]==0)
                            flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]=1,que.push(temp);
 
                        temp=pour_b2a(fir,i+1,i);
                        if(flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]==0)
                            flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]=1,que.push(temp);
                    }
                    else
                    {
                        temp=pour_a2b(fir,1,3);
                        if(flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]==0)
                            flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]=1,que.push(temp);
 
                        temp=pour_b2a(fir,3,1);
                        if(flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]==0)
                            flag[temp.cnt_a][temp.cnt_b][temp.cnt_c]=1,que.push(temp);
                    }
                }
            }
            if(!f)printf("no\n");
        }
    }
 
 
    #ifdef test
    clockid_t end=clock();
    double endtime=(double)(end-start)/CLOCKS_PER_SEC;
    printf("\n\n\n\n\n");
    cout<<"Total time:"<<endtime<<"s"<<endl;        //s为单位
    cout<<"Total time:"<<endtime*1000<<"ms"<<endl;    //ms为单位
    #endif //test
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值