五、母亲的牛奶(cow.cpp)
【题目描述】
农民约翰有三个容量分别是A,B,C升的桶,A、B、C分别是三个从1到20的整数。
最初,A和B桶都是空的,而C桶是装满牛奶的。
有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了。由于节约,牛奶不会有丢失。
写一个程序去帮助约翰找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。
【输入】
第1行:3个整数A,B和C。
【输出】
第1行:升序地列出当A桶是空的时候,C桶牛奶所剩量的所有可能性。
【样例输入】
2 5 10
【样例输出】
5 6 7 8 9 10
----------------------------------------------------------------------------------------------------
这道题……应该,可能,也许,是广搜简单一点。但是,我用的深搜……花了四五十分钟……
真的不会广搜,找时间补补。
大体思路:
就递归,定义vis数组(三维)判重,if(!vis)return; 然后只要此处容量没有满,就将其他两个(也要满足不为空)往这里面倒。总共3个大if,6个小if,还有n个问号表达式(事实上老师不推荐用,容易出问题,换成if也无妨,但有一点点复杂)。
代码如下:
#include<cstdio> 5 int a,b,c; int vis[22][22][22]; void milk(int x,int y,int z)//xyz分别是abc桶剩余的数量 { if(vis[x][y][z])//判重 return; vis[x][y][z]=1;//发现一种就记录一种 if(x<a)//判断当前桶是否已满 { if(y)//其他两个桶只要不为空就能往里倒 milk(a>x+y?x+y:a,a>x+y?0:y-(a-x),z);//这里到下面去解释 if(z) milk(a>x+z?x+z:a,y,a>x+z?0:z-(a-x)); } if(y<b)//以此类推 { if(x) milk(b>x+y?0:x-(b-y),b>x+y?x+y:b,z); if(z) milk(x,b>y+z?y+z:b,b>y+z?0:z-(b-y)); } if(z<c) { if(x) milk(c>x+z?0:x-(c-z),y,c>x+z?x+z:c); if(y) milk(x,c>y+z?0:y-(c-z),c>y+z?y+z:c); } } int main() { freopen("cow.in","r",stdin); freopen("cow.out","w",stdout);//文件输入输出 scanf("%d%d%d",&a,&b,&c); milk(0,0,c); for(int i=b;i>=0;i--) for(int j=0;j<=20;j++)//数据中最大c为20,且需从小到大(升序)输出,所以从0到20查 if(vis[0][i][j]) printf("%d ",j);//没有处理最后的空格 return 0; }
关于问号表达式应该都知道,然后我拿出一个来解释那个递归:
milk(a>x+y?x+y:a,a>x+y?0:y-(a-x),z);
首先第一个参数:
a>x+y?x+y:a,因为此处是将y(b)桶倒至x(a)桶,所以这里是处理x桶。当将y桶全部倒入x桶都没有达到最大容量(a>x+y)时,就将y全部倒入,返回x+y;反之则是x桶满了,也就是a,所以返回a。
第二个参数:
a>x+y?0:y-(a-x),同上,这里是处理y桶。同上,全部y桶倒入后自然是返回0;反之,也就是y桶没倒完,x桶满了,y桶就只减去x桶还差多少倒满的值(a-x)就行了,返回y-(a-x)。
不关第三个参数的事,所以不变。
By WZY