一道华为简单算法题记录-汽水瓶

一道华为简单算法题记录-汽水瓶

背景

今天公司同事提到了面试一位新人的时候提出的华为的一道题,感觉有点意思,记录下吧。
假设一瓶汽水售价1元,3个瓶盖可以换一瓶汽水,2个瓶子可以换一瓶汽水,问20元可以喝多少汽水。

解法描述

看到这个题目,最直接的做法,就是写个程序,模拟买汽水-换汽水的过程,直到剩余的瓶盖或者瓶体买不到汽水。

然而这样写似乎有点太麻烦了,依稀记得这种换汽水问题是小学的必考题,直到初中学了方程才学会智能的解法。小学时我们经常会遇到这样的问题,汽水1元,2个瓶子可以换一瓶汽水,10元能喝到多少瓶汽水。然后就可以在纸上模拟整个过程了,答案是20瓶。这种题技巧是如果最后只剩下一个空瓶子的时候要向老板借一瓶,然后凑2个瓶子换一瓶汽水,再把最后的2个瓶子还给老板。

到了初中,我们学会了列方程解决问题。就换了一种思路,不再一步步推算了。其实从题目描述来看,瓶子和汽水都是有价值的,而作为消费者我们的目的是为了喝汽水,所以为了喝到最多的汽水,我们要把所有的钱都换成汽水。
设汽水的价值是x,汽水瓶子的价值是y。
则有
{x+y=12y=x+y \left\{ \begin{array}{lr} x + y = 1 \\ 2y= x + y \end{array} \right.
从而解得
x=12y=12 \begin{array}{lr} x = \dfrac{1}{2}\\ y = \dfrac{1}{2} \end{array}
所以能喝到的汽水是10/12=2010/\dfrac{1}{2}=20瓶。
那么华为的题目也可以用类似的办法做。设瓶盖的价格是x,瓶体的价格是y,汽水的价格是z。
那么我们可以列出下面方程组
3x=x+y+z2y=x+y+z1=x+y+z \begin{array}{lr} 3x &= x+y+z\\ 2y &= x+y+z\\ 1 & = x + y + z \end{array}
解得
x=13y=12z=16 \begin{array}{lr} x = \dfrac{1}{3}\\ y = \dfrac{1}{2}\\ z= \dfrac{1}{6} \end{array}
所以如果我们可以把钱全部转化为汽水的话,换句话说,允许向老板赊账的话则可以喝20/16=12020/\dfrac{1}{6}=120瓶。
然而,这道题其实不允许赊账。所以直接return 6*x是不行的。
所以老老实实写程序

#include <stdio.h>
int main(){
int money;
const  int price = 1;
while(1){
	scanf("%d",&money);
	int result,hat,body;
	result= money/price;
	hat = result;
	body = result;
	int tmp = 0;
	while(!(hat<3 && body < 2)){
		tmp = hat/3 + body/2;
		result += tmp;
		hat = hat % 3 + tmp;
		body = body % 2 + tmp;
	}
	printf("%d\n",result);
}
return 0;
}

进一步思考

我们开始定义一下喝汽水的步骤,
(1) 首先将钱换成汽水,将汽水喝完。
(2) 尽可能多的将手中所有的瓶子和瓶盖换成汽水,如果换不了则结束。
(3) 继续喝完所有汽水,然后重复步骤二。
按照上述步骤喝汽水,我们可以保证能喝到最多的汽水,最后剩余的瓶子和瓶盖也肯定换不了汽水。
然后开始考虑问题复杂在哪里,在不允许赊账的情况下,最后可能会剩下瓶子和瓶盖转化不成汽水,所以肯定达不到120瓶。
那么最后会剩几个瓶子和瓶盖呢。分类讨论下
(1)瓶子数大于等于2或者瓶盖大于等于3的情况。不可能出现,因为此时还可以继续换汽水。
(2)只剩下瓶子或者只剩下瓶盖的情况。不可能出现,假设按照上述步骤喝,到达最后一步不能再换取新的汽水之前,肯定至少喝完了一瓶汽水,那么肯定剩下至少一个瓶子喝一个瓶盖。
(3)1个瓶子,1个瓶盖。只剩一个瓶子一个瓶盖,说明在到达最后一步之前的喝汽水的步骤时,我们既没有瓶盖也没有瓶子,只有一瓶汽水。那么在获得这一瓶汽水之前的换汽水的步骤里,肯定只有3个瓶盖或者2个瓶子,这喝我们的情况2是一样的,显然是不可能存在的。所以这一瓶汽水只能是在步骤一中花钱买的,即只有1元钱的时候的情况。 所以当只有1元钱时,我们最终会剩下一个瓶子和瓶盖,一共价值为12+13=56\dfrac{1}{2}+\dfrac{1}{3}=\dfrac{5}{6}元。那么只有16\dfrac{1}{6}元转化为了汽水,也就是只能喝一瓶。
(4)1个瓶子,2个瓶盖。 经过上述讨论,只剩下了这一种情况,即只要不是1元钱,肯定最后剩下1个瓶子2个瓶盖,价值为12+23=76\dfrac{1}{2}+\dfrac{2}{3}=\dfrac{7}{6}元。所以最后相比较可以赊账的情况,会少买7瓶。
下面写程序:

#include <stdio.h>
int main(){
int money;
const  int price = 1;
while(1){
	scanf("%d",&money);
	if(money == 1) printf("1\n");
	else printf("%d\n",6 * money - 7);
}
return 0;
}

推广

假设我们有m元,汽水价格为p,h个瓶盖可以换取一瓶汽水,b个瓶子可以换一瓶汽水。那么可以喝多少瓶汽水呢。
暂时还没有找到很好的规律,随着h和b的增大,可能最终的情况多了起来。如果每次输入都进行更改的话,能想到的还是只是去模拟买汽水的步骤。类似于第一份代码,只不过,把hat和body的限制换成输入。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章