【BFS】巧妙取量

简介: 【BFS】巧妙取量(c++基础算法)

这道题呢,不是很难,但有那么亿点繁琐,我数了一下,共有七层的嵌套。

本专栏上一篇:【BFS】海上救援任务(c++基础算法)


目录

一.读题

①题面

②题意

二.观察与分析

①倒入的操作

②一个特殊情况(特判)

③标记

④因为多组数据

三.AC代码

最后


一.读题

①题面

【宽搜(难度:6)】巧妙取量

题目描述

【题意】

   有三个容器,容量分别为 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了。

【输入格式】

   输入有多组测试数据。

   输入a,b,c, k四个正整数( 100 > = a > b > c > = 1 , 1 < = k < 100 )

【输出格式】

   如果能得到k就输出两行

   第一行"yes",第二行为最少的次数,否则输出"no"。

【样例输入】

10 7 3 5

【样例输出】

yes

8

②题意

通过不断地倒入倒出,直到数组中一个量为k,输出最少的操作步数


二.观察与分析

①倒入的操作

针对这题,仅提供三个容器,并且每次只能将一个容器中的油倒入另一个容器,所以由每个状态可以得到的新的状态只有六个。

那么,我们就可以循环i 1-3,j 1-3,模拟i向j倒水。

Ⅰ判断不过要注意有两种情况,这两种情况都是不可以进行倒油操作的:i==j(自己给自己倒油,开什么玩笑);a[i]==0(自己都没油了,还给别人倒油?搞笑)

Ⅱ倒油然后,就可以开始倒油了。定义一个T记录a[j]离倒满所需的油数。这时就会遇到又会两种情况:a[j]没被倒满,a[i]已经空了;a[j]已经满了,而a[i]还有油或刚好倒完。明白这些,程序设计就很简单了……

Ⅲ入队 在此之后,就是熟悉的不能再熟悉的宽搜模板代码了。

现在,看看程序:

iffor(int i=1;i<=3;i++)
          {
              if(q.front().a[i]>0)
              {
                  for(int j=1;j<=3;j++)
                  {
                      node sy;
                      sy=q.front();
                      sy.ans ++;
                      if(i!=j)
                      {
                          int T=t.a[j]-sy.a[j];
                          if(sy.a[i]>T)
                          {
                              sy.a[j]=t.a[j];
                              sy.a[i]=sy.a[i]-T;
                          }
                          else
                          {
                              sy.a[j]+=sy.a[i];
                              sy.a[i]=0;
                          }
                          if(!bo[sy.a[1]][sy.a[2]][sy.a[3]])
                          {
                              bo[sy.a[1]][sy.a[2]][sy.a[3]]=1;
                              if(sy.a[1]==k||sy.a[2]==k||sy.a[3]==k)
                              {
                                  flag=true;
                              }
                              q.push(sy);
                          }
                      }
                  }

image.gif

②一个特殊情况(特判)

当目标状态与初始状态一样时,要直接输出一个yes,0(因为当出现上述情况时,无需操作即可达到目标状态)

③标记

因为有可能达不到目标状态,因此需要用bool数组(初始值为false)当到达目标状态时,标记为true。详情请看后面的代码。

④因为多组数据

如题,因为有多组数据,我们要做一些烦人的操作。

1.输入

要用到EOF这样的东西。

EOF:当你将一个文件输入到一个函数中时,它总是会返回一个状态,它是读出来的,或者是失败的,它是如何表达的?所以就约定俗成定义一个标识符表示这个状态,就有了EOF(end of file)。如果第一个参数是 NULL (null),那么该 scanf函数就可以返回 EOF,否则将会传回已被成功地设置和分配的参数数目(>=0)。所以,这个循环,将是一个死循环。(while:实现循环表达的一种,循环的内容只能是一个语句,可以是一个简单的语句,还可以是复合语句。)

2.初始化

用memset()函数初始化数组,用下面的语句初始化队列。

 

while(!q.empty())
      {
          q.pop();
      }

image.gif

很简单,原理就不用我讲了。。。


三.AC代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    int ans,a[10];
};
queue<node>q;
int k;
bool bo[105][105][105],flag;
int main()
{
    node t,p;
    while(scanf("%d%d%d%d",&t.a[1],&t.a[2],&t.a[3],&k)!=EOF)//多组数据
    {
        flag=false;
        memset(bo,0,sizeof(bo));
      bo[t.a[1]][t.a[2]][t.a[3]]=1;
      p.ans=0;
      p.a[1]=t.a[1];
      p.a[2]=p.a[3]=0;
      q.push(p);
      if(q.front().a[1]==k||q.front().a[2]==k||q.front().a[3]==k)
      {
          printf("yes\n%d\n",0);
            continue;
      }//特判 
      while(!q.empty())
      {
          for(int i=1;i<=3;i++)
          {
              if(q.front().a[i]>0)
              {
                  for(int j=1;j<=3;j++)
                  {
                      node sy;
                      sy=q.front();
                      sy.ans ++;
                      if(i!=j)
                      {
                          int T=t.a[j]-sy.a[j];
                          if(sy.a[i]>T)
                          {
                              sy.a[j]=t.a[j];
                              sy.a[i]=sy.a[i]-T;
                          }
                          else
                          {
                              sy.a[j]+=sy.a[i];
                              sy.a[i]=0;
                          }
                          if(!bo[sy.a[1]][sy.a[2]][sy.a[3]])
                          {
                              bo[sy.a[1]][sy.a[2]][sy.a[3]]=1;
                              if(sy.a[1]==k||sy.a[2]==k||sy.a[3]==k)
                              {
                                  flag=true;
                              }
                              q.push(sy);
                          }
                      }
                  }
              }
          }//遍历每一种倒法 
        if(flag) break;
        q.pop();
      }
      if(flag)
      {
          printf("yes\n%d\n",q.back().ans);
      }
      else
      {
          printf("no\n");
      }
      while(!q.empty())
      {
          q.pop();
      }
    }
}

image.gif


最后

最近在训练,就水水文章吧(好像一直在水……)。。。

给个小红心吧!!!😁

相关文章
|
3月前
|
存储 算法
BFS算法的实现
BFS算法的实现
48 1
|
5月前
|
存储 算法
算法BFS经典例题(迷宫,多源BFS,BFS解决拓扑排序,FloodFill算法)
算法BFS经典例题(迷宫,多源BFS,BFS解决拓扑排序,FloodFill算法)
|
算法
广度优先遍历(BFS):逐层探索图的算法奥秘
在图论中,广度优先遍历(Breadth-First Search,BFS)是一种图遍历算法,它以一种逐层的方式探索图的节点。通过从起始节点开始,逐层向外扩展,BFS能够帮助我们解决许多与图相关的问题。
126 0
青蛙跳台阶问题的简单实现与理解(递归实现)
青蛙跳台阶问题的简单实现与理解(递归实现)
|
机器学习/深度学习 算法 测试技术
C++算法:深度优先搜索(BFS)的原理和实现
C++算法:深度优先搜索(BFS)的原理和实现
|
机器学习/深度学习 算法 测试技术
C++算法:01BFS最短距离的原理和实现
C++算法:01BFS最短距离的原理和实现
|
机器学习/深度学习 算法 定位技术
BFS经典例题详解
BFS经典例题详解
143 0
|
人工智能 算法 机器人
【算法基础】深搜(下)
【算法基础】深搜(下)
84 0
|
算法 机器人 C语言
【算法基础】深搜(上)
【算法基础】深搜(上)
99 0