这道题呢,不是很难,但有那么亿点繁琐,我数了一下,共有七层的嵌套。
本专栏上一篇:【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();
}
}
}
最后
最近在训练,就水水文章吧(好像一直在水……)。。。
给个小红心吧!!!😁
334

被折叠的 条评论
为什么被折叠?



