这道题呢,不是很难,但有那么亿点繁琐,我数了一下,共有七层的嵌套。
本专栏上一篇:【BFS】海上救援任务(c++基础算法)
目录
一.读题
①题面
【宽搜(难度: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); } } }
②一个特殊情况(特判)
当目标状态与初始状态一样时,要直接输出一个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(); }
很简单,原理就不用我讲了。。。
三.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(); } } }
最后
最近在训练,就水水文章吧(好像一直在水……)。。。
给个小红心吧!!!😁