【NOIP普及组】【DFS】2016年模拟考试(9.3)——母亲的牛奶

五、母亲的牛奶(cow.cpp

【题目描述】

农民约翰有三个容量分别是ABC升的桶,ABC分别是三个从120的整数。

最初,AB桶都是空的,而C桶是装满牛奶的。

有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了。由于节约,牛奶不会有丢失。

写一个程序去帮助约翰找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。

【输入】

1行:3个整数ABC

【输出】

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值