问题 Q(1208): 【基础算法】倒酒问题

来源:互联网 发布:有意思的书推荐 知乎 编辑:程序博客网 时间:2024/04/28 06:55

问题 Q(1208): 【基础算法】倒酒问题

时间限制: 1 Sec 内存限制: 64 MB
提交: 49 解决: 15
[提交][状态][我的提交]
题目描述

有一个大酒瓶和三个容量分别为a,b,c两的大酒杯,主人把容量为a的酒杯倒满后,两个客人提出大家先各喝一两,而且要主人先喝,这样就要求主人通过三个酒杯最后能在容量为b,c的酒杯中各倒上一两酒(主人可先喝倒出来的一两,可以将酒倒入酒瓶,但不可以从酒瓶中倒出)。主人喝酒的操作不计入步数。且主人可以拿任何一个杯子喝酒,只要其中刚好是1两酒。
输入

第1行:3个整数a,b,c表示三个酒杯的容量,(a,b,c均小于100,且b < a, c < a)
输出

表示所需最少步数。

最开始酒杯中都没有酒,第一步必须将酒杯A倒满。

若无解,则输出no solution
样例输入

(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

4 3 1

样例输出

4

提示

答案解释:

格式为:

步数:a b c 主人

1:4 0 0 0

2:1 3 0 0

3:1 2 0 1

4:1 1 1 1

[提交][状态][讨论版]

#include<cstdio>#include<queue>#include<algorithm>using namespace std;int m[3]; //三个酒杯的容量,不是酒哦。int vis[105][105][105][2]; //用于判重的数组struct cup{int c[4],o,t; //c数组存储各杯装的酒量,o作为主人是否喝酒的标记,t为倒酒的步数cup(){c[1]=c[2]=c[3]=o=0;}//这是结构体中cup的构造函数cup(),它会跟结构体一起执行,实现初始化的目的 。c数组表示杯中的酒的//数量。void pour(int b,int e){int u=c[b]+c[e];c[e]=min(m[e],u);c[b]=u-c[e];} //这是最核心的代码,酒是怎么从一个杯子c[b]倒入到另一个//杯子c[e]的void drink(int k){c[k]=0;o=1;} //主人喝完一两酒了,喝了就标记o=1void come(int k){c[k]=0;} //把杯子倒空,模拟倒回酒瓶bool V(){return !vis[c[1]][c[2]][c[3]][o];} //如果这组数据没有使用过,就返回1void F(){vis[c[1]][c[2]][c[3]][o]=1;} //标记这组数据(c[1]、c[2]、c[3]、o)(或者把它们看作一个结点)已经使用了}s;queue<cup>que; //定义类型为结构体cup的FIFO队列quevoid bfs(){que.push(s);//把结构体变量s放入队列s.F(); //构造函数cup()会执行,且让vis[0][0][0][0]=1;while(!que.empty()) //当队列不空{cup x=que.front(); //从队首元素开始处理if(x.c[2]==1&&x.c[3]==1&&x.o) //如果每b,c杯子都是1两,且主人喝过1两,就输出x.t{printf("%d",x.t); //输出答案:一共经过了x.t步//printf("\n the last step: %d %d %d \n",x.c[1],x.c[2],x.c[3]); //最后一步后,a,b,c杯子中的情况:1,1,1return; //return用于结束整个函数,exit()结束整个程序}for(int i=1;i<=3;i++) //倒出的三个杯子(其实只有2个,自己不能给自己倒){cup nx; //重新声明结构体变量nx,即重新初始for(int j=1;j<=3;j++) //接受的三个杯子(其实只有2个,自己不能给自己倒){nx=x;nx.t++;//步数加1if(i!=j) //不能自己倒给自己,只能倒给别人{nx.pour(i,j); //开始倒酒,把第i杯倒给第j杯,这就是为什么要用两个for循环的原因:实现相互倒酒if(nx.V()) //没有访问过{nx.F(); //标记为已访问que.push(nx); //队尾压入一个新元素}}}nx=x; //这一趟入队的原因是题目说可以把酒倒入酒瓶,倒回酒瓶了就改变了局势,应该把此结点入队nx.t++; //步数加1nx.come(i); // c[i]=0,即倒空杯子,模拟把酒倒回酒瓶,改变了局势,应该把此结点入队if(nx.V())que.push(nx);nx=x;//这一趟入队的原因是主人先喝1两酒,改变了局势,应该把此结点入队if(x.c[i]==1&&x.o!=1) //如果杯中是一两酒,且没有喝过(o的初值为0),这步按题意,不能计入步数{nx.drink(i); //主人喝下这1两酒,且让c[i]=0,表示c[i]杯已经为空,且让o的值为1,作为主人已经drink的标记if(nx.V()) //如果没有访问过vis[c[1]][c[2]][c[3]][o] (因为主人喝后,c[i]=0,杯中的酒量已经更新,需要存储到队列中)que.push(nx); //入队尾}}que.pop();//删除队首元素}printf("no solution");}int main(){//freopen("d:\\out.txt","w",stdout);scanf("%d%d%d",&m[1],&m[2],&m[3]);s.c[1]=m[1]; //成员数组变量c元素1的值为m[i], m[1]的值为c[1]的,因为是装满的。s.t=1;bfs();}
原创粉丝点击