“汽水三换一”问题的两种问法及巧妙解答

此题今年我在包括360在内的三家公司的笔试面试中遇到过,总结了此题的两种问法及巧妙解决方案,方便大家应对招聘或者当个智力题开动下思维也好。

问法一:三个空瓶换一瓶汽水,某班买了30瓶汽水,要保证每人喝一瓶汽水,最多可以供给多少名同学?
问法二:三个空瓶换一瓶汽水,某班有30名同学,要保证每人喝一瓶汽水,最少需要买多少瓶水?

此题在我小学三年级的时候就在某“智力”书上看过,让我印象这么深的原因是因为它有一个巧妙的思想: 比如剩两个空瓶子了,你可以再像老板赊一瓶汽水,喝完可以把三个空瓶子给老板(相当于一瓶汽水),所以剩两个空瓶子的时候也可以喝到一瓶汽水!

现在我们来看相对简单的问法一,因为它是正着问的,逻辑推理上很顺,比如我们买了30瓶汽水,首先可以供给30名同学,剩下30个空瓶可以换10瓶汽水可以供给同学总数为30+10名,接下来10个空瓶可以换3瓶汽水供给总数为30+10+3名,最后剩了4个空瓶可以再供给1名同学,最后剩下两个空瓶,根据开始的“思想”还可以供给1名同学一共可以供给30+10+3+1+1 = 45名.

用程序实现这个算法也很简单,供大家参考:
public class SanHuanYi {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		int init_bottle_num = 30;//初始汽水的数量
		int person_num = 0;//能供给同学的数量
		
		person_num = getAllBottleNum(init_bottle_num);
		System.out.println(person_num);
		
	}
	static int getAllBottleNum(int bottle_num){
		if(bottle_num <= 0)
			return 0;
		int all_num = bottle_num;//all_num最终数量
		while(bottle_num >= 3){
			int temp = bottle_num / 3;
			all_num += temp;
			bottle_num = temp + bottle_num % 3;
		}
		all_num += bottle_num == 2 ? 1: 0;//剩两瓶总数量就加1
		return all_num;
	}

}
问法一还有更巧妙的解法,先卖个关子,最后再说,也许您看完问法二自己也能想出来。

问法一还算比较简单,我笔试面试遇到的都是问法二,这个问法似乎就得逆着想了,我最初的想法是比如供给30个同学,似乎买20瓶,再根据"三换一"原则感觉上总数跟30差不多,再在20附近取数比如19,21...最终找到一个需要汽水最小的数。当然这是一个正确的解法。但在笔试中不可能花费大量的时间算一个小题,也不可能在面试中用“拙劣”的方法吸引到面试官。所以介绍一个“分组”算法来解决这个问题。
比如需要供给30名同学,根据“N换一”问题把同学分成“30/N”组,比如此题N=3,我们就把人分成30/3 = 10组,我们假设按顺序供给他们,第一组我们需要供给3瓶汽水,等第一组喝完我们手里有了3个空瓶子正好可以换1瓶汽水,所以我们供给第二组的时候只要再买两瓶汽水就够了!当第二组喝完,我们又有了3个空瓶子,依次类推。。。直到最后一组,我们需要买3+ 2 *(10-1) = 21瓶汽水,但是最后剩下3个空瓶可以,所以我们可以少买一瓶就是20瓶就够了(也就是说该第30名同学喝汽水时手里有了两个空瓶,根据最开始的“思想”可以再换一瓶)。但如果一共31名同学,分组完还剩一人,这时我们正好把最后一组喝完剩下的3个空瓶子给他,结果就是21瓶;如果一共32名同学,只好再多买一瓶了,总数为22瓶。 总结:先对总人数分Sum/3个组,然后可以利用公式 3+2*(Sum/3-1)获得汽水总瓶数,如果分组后没有余下人就用总瓶数减1,如果余下1个人,总瓶数不变;如果余下2个人;总瓶数加1
我们最后可以写个简单的程序模拟这个过程:
public class SanHuanYi {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int person_num = 30;//需要供给的人数
		int all_bottle_num = getLeastBottle(person_num);
		System.out.println(all_bottle_num);
		
	}

	static int getLeastBottle(int person_num){
		
		if(person_num <= 0)
			return 0;
		if(person_num > 0 && person_num < 3)
			return person_num;
		int sum = 0;		
		int group_num = person_num / 3;//能够分的组数
		int yushu = person_num % 3;//分组完,剩余的人
		sum = 3 + (group_num-1) * 2;
		if(yushu == 0){
			sum--;
		}else if(yushu == 1){
			
		}else{
			sum++;
		}
		
		return sum;
	}
}

好了,我们现在回头看看问法一的巧妙解法:买了30瓶汽水,先可以供给30名同学,剩了30个空瓶子,我们还是利用那个“思想”,找15个同学每人分两个空瓶子,让他们自己去找老板,那么他们都能喝到汽水,所以直接用30+15 = 45就完了!


==================================================================================================

  作者:nash_  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/nash_/article/details/8235632

===================================================================================================

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值