非常可乐
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 21525 Accepted Submission(s): 8742
Problem Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出"NO"。
Sample Input
7 4 3
4 1 3
0 0 0
Sample Output
NO
3
Author
seeyou
Source
Recommend
题意:题目给出三个数据S,N,M,并且S==N+M; 问可乐是否能够平分,如果能够平分的话花,那么倒可乐的最少次数是多少,如果不能平分,那么就输出NO。
思路:有三个杯子倒水,无非就6种情况:s-->n,s-->m;n-->s,n-->m;m-->s,m-->n; 就这6种倒水的情况,我用号1、2、3来模拟三个杯子,双重循环来模拟倒水的杯子还互相之间倒水的这6种状态,而且每一次倒水的时候都是从最初始状态开始倒,
sign数组来标记倒水的状态:从某一初始状态开始,模拟杯子之间的倒水过程,用sign标记,来避免有重复的倒水状态被多记录次数和被推入队列。
pour函数来模拟倒水的过程:模拟的是a往b种倒水,下标代表倒水的杯子;如果总共的水量sum是>=b杯的,那么就把谁倒入b杯中,剩下的水还是在a杯中;如果总共的水量sum是<b的,那么就把全部的水都倒入b杯中,然后a杯就空了。
当达到能够平分的条件时,就输出倒水的次数。
这一个题目还有一个类似的题目:倒水还要输出路径链接
但是对于这个题目,我理解的还是不够透彻,不够深刻,不太明白为什么在main函数中,要先把2、3杯子排序,有的说这样是为了方便bfs判断的条件
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int v[5];
int sign[110][110][100];
struct cup//记录遍历中3个水杯容藏可乐情况
{
int v[5];
int step;
}temp;
void pour(int a,int b)//倒水函数,把a杯子中的可乐倒到b杯子中
{
int sum=temp.v[a]+temp.v[b];
if(sum>=v[b])//能把b杯倒满,剩下的还是在a杯
temp.v[b]=v[b];
else
temp.v[b]=sum;//全部倒入b杯中 ,那么a杯中就为 0了
temp.v[a]=sum-temp.v[b];
}
void bfs()
{
int i,j;
queue<cup>q;
cup cnt;
cnt.v[1]=v[1]; //给水杯赋初值
cnt.v[2]=0;
cnt.v[3]=0;
cnt.step=0;
q.push(cnt);
memset(sign,0,sizeof(sign));
sign[v[1]][0][0]=1; //赋值之后并标记,代表这一种情况已经有过了
while(!q.empty())
{
cnt=q.front();
q.pop();
if(cnt.v[1]==cnt.v[3]&&cnt.v[2]==0)
{
printf("%d\n",cnt.step);
return ;
}
for(i=1;i<4;++i)
{
for(j=1;j<4;++j)
{
if(i!=j)//自己不倒水给自己
{
temp=cnt;//每个水位情况都要把所有操作枚举一遍,所以都要赋值为原始水位情况
pour(i,j);//倒水i倒往j,这一函数就是来模拟倒水的过程
printf("temp.v[1]=%d temp.v[2]=%d temp.v[3]=%d\n",temp.v[1],temp.v[2],temp.v[3]);
if(!sign[temp.v[1]][temp.v[2]][temp.v[3]]) //如果这一种倒水情况还没有倒过,那么就把这一种情况标记,然后再做以下操作
{
temp.step++;
q.push(temp);
sign[temp.v[1]][temp.v[2]][temp.v[3]]=1;
}
}
}
}
}
printf("NO\n");
}
int main()
{
while(scanf("%d%d%d",&v[1],&v[2],&v[3])&&v[1]||v[2]||v[3])
{
if(v[2]>v[3])
{
int t=v[2];
v[2]=v[3];
v[3]=t;
}
bfs();
}
return 0;
}