从一道互联网面试题(搬香蕉)说开去


Table of Contents

  • 1 问题描述
  • 2 问题分析
  • 3 程序代码

1 问题描述

A、B两座城市相距1000Km,我们有3000个香蕉要从A城市运往B城市,已知一头大象一次最多能运1000个香蕉, 而且大象每次走1Km要吃掉一个香蕉,如果香蕉被吃完了,大象就不能再继续往前走。请问,你最终最多能运多少香蕉到B城市?

2 问题分析

当我某一天无意中在网页上看到这样的一道题,感慨良多。多年前我在某互联网公司实习的时候,终面时也被问到了一 道同样的智力题,只是当时题目的描述并不是大象搬香蕉,而是猴子搬香蕉。现在换了下描述对象和参数,换汤不换药。 回到这道题,问题的关键在哪里呢?先这样想,如果我们一共只有1000个香蕉,是不是很简单呢?因为大象每走一Km 要吃掉一个香蕉,而它最多也可以搬动1000个香蕉,我们可以不用往回走,边走边吃,走完就吃完了。到目的地后还 剩下0个香蕉……

所以仔细地想一下,问题的关键在于,大象并不能一次搬完所有的香蕉,它要走回头路。而回去的时候也是要消耗香蕉的。 在哪里返回便是问题的关键点。当我们有3000个香蕉的时候,一共得走(2*3-1)=5次,假定我们这时移动的距离为x(3) 当我们只有2000个香蕉的时候,一共得走(2*2-1)=3次,移动的距离为x(2), 当我们只有1000个香蕉的时候, 不用回头走路(2*1-1)=1次,距离为x(1). 所以,看到规律了吧。
由上面的分析:
x(n) = 1000/(2*n-1)
1000是大象最多一次能运的香蕉个数, (2*n-1)为每走一公里所消耗的香蕉个数
x(n)为每消耗1000根香蕉,大象能把所有香蕉搬运的公里数
n最大为 3000/1000 = 3
1000 = x(n) + x(n-1) + ...
最后剩下的香蕉数为:
3000 - (2*n-1)*x(n) - (2*n-3)*x(n-1)...
由于这里的数字比较简单,我们口算都能算出来:
x(3)= 1000/5 = 200
x(2)= 1000/3 = 333.33 多出一个香蕉,不要了,回去取得不偿失
x(1)= 1000 - 200 - 333 = 467
最后剩下的香蕉数为:
3000 - 1000 - 1000 - 467 = 533

3 程序代码

有了上面的分析,可以很容易的写出程序。下面是Python的实现
# -*- coding: utf-8 -*-

# n means the count of rounds
# It returns the cost of rounds
def cost(per_cost, n):
    return (2*n - 1) * per_cost

# calc how long we could go with cost(n) per kilometer
def f(max_load, per_cost, n):
    s = max_load / cost(per_cost, n)
    return s

# all_load, the number of all banana 
# distance, the distance between the cities
# max_load, the max loading elephant could carry
# per_cost, the cost of banana per KM
def calc_remain(all_load, distance, max_load, per_cost):
    remain_dist = distance
    nmax = all_load / max_load
    all_cost = 0

    while nmax > 0:
        if remain_dist > f(max_load, per_cost, nmax):
            remain_dist -= f(max_load, per_cost, nmax)
            all_cost += max_load
            nmax -= 1
        else:
            all_cost += cost(per_cost, nmax) * remain_dist
            remain_dist = 0
            nmax = 0
    print 'Remain load: %d, remain distance %d' % \
            ((all_load - all_cost), remain_dist)
    return (all_load - all_cost), remain_dist


if __name__ == '__main__':
    all_load = 3000
    distance = 1000
    max_load = 1000
    per_cost = 1

    rload, rdist = calc_remain(all_load, distance, max_load, per_cost)

4 思维扩展

有了上面的程序,我们可以很快地解决这个问题的其它变种。比如说大象至少要能一次搬多少个香蕉才能保证到目的地后 香蕉有剩于。如果问题这样出的话应该会难一点点。 同样的,调用我们上面已经写好的代码,可以很快地解决这个问题。

if __name__ == '__main__':
    all_load = 3000
    distance = 1000
    max_load = 1000
    per_cost = 1
    
    for i in range(50, 1000):
        rload, rdist = calc_remain(all_load, distance, i, 1)
        if rdist == 0:
            print "i = %d." % i
            break
从一道互联网面试题(搬香蕉)说开去_第1张图片

HTML generated by org-mode 6.31a in emacs 23

你可能感兴趣的:(智力题,Python,C/C++)