今天班级聚餐,喝得二麻二麻的,回寝室后强行吐了一发,慢慢清醒后补上了这几天因为耍守望屁股而欠下的帐,恩,我爱学习,学习爱我
这道题体现了BFS的精髓:给定初始状态跟目标状态,要求从初始状态到目标状态的最短路。
这是一道BFS,每次倒可乐动作可以看为:
从瓶中向第一个杯子倒,向第二个杯子倒;
从第一个杯子向瓶子倒,向第二个杯子倒;
从第二个杯子向瓶子倒,向第一个杯子倒。
这六种情况就确定了搜索方向。
我的方法是每次要倒得时候判断,该容器可不可以倒可乐(该容器满没满)
然后是细节处理:
例如如果从第一个杯子向第二个杯子倒。
①第二个杯子是否可以倒可乐(是否满了)
②第一个杯子是否是空的
③第一个杯子向第二个杯子倒完后,会不会溢出。
④第一个杯子如果剩余,剩余多少(由第一个杯子原来是否有可乐决定)
遍历数组,vis此处可以建立三维数组,让各个容器内可乐容量作为三个下标,当成某一个状态。
我开始以为能够想到用BFS还是不错了,后来我百度了一下这道题,发现有个大神用数论知识解决了这道题,和我的100多行代码相比,别人只用了十多行代码,(大神博客http://blog.csdn.net/v5zsq/article/details/52097459)比起来,我写的代码真的是又长又臭。。。。。。。心情无比惆怅:
不说了,依然坚强地上我的一百行代码:
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int S,N,M;
int vis[101][101][101];
struct node{
int w1,w2,w3; //瓶子,第一个杯子,第二个杯子中含有的水的体积
int num; //倒的次数
};
void Bfs(){
memset(vis,0,sizeof(vis));
queue<node>q;
node s,e;
s.w1=S;
s.w2=0;
s.w3=0;
s.num=0;
vis[S][0][0]=1;
q.push(s);
while(!q.empty()){
s=q.front();
q.pop();
if(s.w1==S/2&&(s.w2==S/2||s.w3==S/2)) //饮料被平分的标志
{
printf("%d\n",s.num);
return;
}
if(s.w1!=0){ //当瓶子中有饮料时
if(s.w2<N) //往杯子1中倒
{
if(s.w1<=N-s.w2){ //不能将杯子1倒满
e.w1=0;
e.w2=s.w2+s.w1;
e.w3=s.w3;
}
else { //能将杯子1倒满
e.w1=s.w1-(N-s.w2);
e.w2=N;
e.w3=s.w3;
}
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
if(s.w3<M) //往杯子2中倒
{
if(s.w1<=M-s.w3){ //不能将杯子2倒满
e.w1=0;
e.w3=s.w3+s.w1;
e.w2=s.w2;
}
else { //能将杯子2倒满
e.w1=s.w1-(M-s.w3);
e.w3=M;
e.w2=s.w2;
}
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
}
if(s.w2!=0){ //同上
if(s.w1<S)
{
e.w2=0;
e.w1=s.w2+s.w1;
e.w3=s.w3;
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
if(s.w3<M)
{
if(s.w2<=M-s.w3){
e.w2=0;
e.w3=s.w3+s.w2;
e.w1=s.w1;
}
else {
e.w2=s.w2-(M-s.w3);
e.w3=M;
e.w1=s.w1;
}
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
}
if(s.w3!=0){ //同上
if(s.w2<N)
{
if(s.w3<=N-s.w2){
e.w3=0;
e.w2=s.w2+s.w3;
e.w1=s.w1;
}
else {
e.w3=s.w3-(N-s.w2);
e.w2=N;
e.w1=s.w1;
}
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
if(s.w1<S)
{
e.w3=0;
e.w1=s.w3+s.w1;
e.w2=s.w2;
if(!vis[e.w1][e.w2][e.w3])
{
vis[e.w1][e.w2][e.w3]=1;
e.num=s.num+1;
q.push(e);
}
}
}
}
printf("NO\n");
return;
}
int main()
{
while(scanf("%d %d %d",&S,&N,&M)!=EOF){
if(!N&&!M&&!S)break;
if(S%2!=0){ //奇数肯定不能平分,因为被子是整数体积大小
printf("NO\n");
continue;
}
if(N==M){ //如果两个杯子的体积相同,肯定只需要倒一次便可平分
printf("1\n");
continue;
}
Bfs();
}
return 0;
}