生活中常常遇到一些比较有趣的问题,有些是脑筋急转弯类的“软问题”,依靠清奇的脑回路才能解决。
而有些则是正宗的“硬问题”,只有拥有缜密的逻辑思维能力的人才能解决。
例如下面这个问题:
啤酒3块钱一瓶,7个瓶盖或者2个空酒瓶可以换一瓶啤酒,小明有15块,最多可以喝几瓶啤酒?
短小精悍的问题
这个问题在网上流传甚广,所以这里稍稍修改了一些参数,避免与BD上可以搜到的答案重复。
我们不考虑小明的酒量,也不考虑小明和店老板关系好,可以赊账等情况,仅从数学角度考虑该问题。
这个问题虽然简短,但是挺“绕人”的:
使用空酒瓶和瓶盖换啤酒时,空酒瓶和瓶盖的数目会减少,但是得到啤酒后,空酒瓶和瓶盖的数目又会增加。
另外,小明还可以自己花钱买啤酒。
空酒瓶、瓶盖、啤酒、钱各个组件彼此纠缠,如果没有清晰的头脑,很容易就迷糊了。
不过,作为程序员,对这类问题应该非常有兴趣,因为这类问题考察的是逻辑思维能力,而程序员普遍对自己的逻辑思维能力自信,也乐于挑战逻辑问题。
解决问题后,一来可以增加自己的成就感,二来还可以锻炼自己解决问题的能力。
所以从编程角度来看,该如何解决这个问题呢?
首先定义一个 Beer 类
<?php /** * 小明喝啤酒 */ class Beer { public $money = 15; //拥有的钱 public $price = 3; //一瓶啤酒的价格 protected $beer = 0; //已经喝啤酒数量 protected $bottle = 0; //空酒瓶数量 protected $cap = 0; //瓶盖数量 }
上述代码描述了小明一开始的状态:
拥有15块钱,一瓶啤酒的价格是3块钱,已经喝了 0 瓶啤酒,手里有 0 个空酒瓶和 0 个瓶盖。
然后我们定义一个函数,这个函数用来描述小明喝一瓶啤酒发生的事
/*喝一瓶啤酒*/ public function drink_one_beer() { // 如果没喝到啤酒 return false; //如果成功喝到啤酒 return true; }
现在设想小明喝到啤酒的情况:
显然,喝到的啤酒数目多了一瓶,空酒瓶和瓶盖也会都多一个,使用PHP语言描述这一过程就是
/*喝一瓶啤酒*/ public function drink_one_beer() { //如果成功喝到啤酒 $this->beer ++; $this->bottle ++; $this->cap ++; return true; }
不过小明要想喝到啤酒也是要付出代价的;
要么是花钱买,要么是用空酒瓶或者瓶盖换,只不过小明得确保自己的钱够用,或者空酒瓶、瓶盖的数目足够多。
使用PHP语言描述这一过程,得到如下代码:
if ($this->cap >= 7) { //七个瓶盖兑一瓶啤酒 $this->cap -= 7; } elseif ($this->bottle >= 2) { //二个空瓶兑一瓶啤酒 $this->bottle -= 2; } elseif ($this->money >= $this->price) { //花钱买啤酒 $this->money -= $this->price; } else { return false; //没喝到啤酒 }
整理一下代码,就可以得到小明喝一瓶啤酒的PHP语言描述了;
/*喝一瓶啤酒*/ public function drink_one_beer() { if ($this->cap >= 7) { //七个瓶盖兑一瓶啤酒 $this->cap -= 7; } elseif ($this->bottle >= 2) { //二个空瓶兑一瓶啤酒 $this->bottle -= 2; } elseif ($this->money >= $this->price) { //花钱买啤酒 $this->money -= $this->price; } else { return false; //没喝到啤酒 } $this->beer ++; $this->bottle ++; $this->cap ++; return true; //喝到啤酒 }
现在喝一瓶啤酒的动作有了,但怎么告诉机器只要小明能喝到啤酒就让他一直喝呢?
再定义一个函数:
public function start_drink() { while ($this->drink_one_beer()) { echo '<br/>还剩 ' . $this->money . ' 块钱; ' . '喝了 ' . $this->beer . ' 瓶啤酒; ' . '拥有 ' . $this->bottle . ' 个瓶子; ' . '拥有 ' . $this->cap . ' 个瓶盖; '; } }
运行下看小明到底能喝多少瓶酒;
答案是小明可以喝 11 瓶啤酒,最后口袋里还剩 0 块钱,剩余 1 个空酒瓶和 4 个瓶盖。
完整代码:
<?php /** * 小明喝啤酒 */ class Beer { public $money = 15; //拥有的钱 public $price = 3; //一瓶啤酒的价格 protected $beer = 0; //已经喝啤酒数量 protected $bottle = 0; //空酒瓶数量 protected $cap = 0; //瓶盖数量 public function __construct($money, $price) { $this->money = $money; $this->price = $price; } /*喝一瓶啤酒*/ public function drink_one_beer() { if ($this->cap >= 7) { //七个瓶盖兑一瓶啤酒 $this->cap -= 7; } elseif ($this->bottle >= 2) { //二个空瓶兑一瓶啤酒 $this->bottle -= 2; } elseif ($this->money >= $this->price) { //花钱买啤酒 $this->money -= $this->price; } else { return false; //没喝到啤酒 } $this->beer ++; $this->bottle ++; $this->cap ++; return true; //喝到啤酒 } public function start_drink() { while ($this->drink_one_beer()) { echo '<br/>还剩 ' . $this->money . ' 块钱; ' . '喝了 ' . $this->beer . ' 瓶啤酒; ' . '拥有 ' . $this->bottle . ' 个瓶子; ' . '拥有 ' . $this->cap . ' 个瓶盖; '; } } } $obj = new Beer(15, 3); $obj->start_drink();