网站最近更新

© 乙回庐 2019. All rights reserved.

喝啤酒的问题

昨天同事在朋友圈里问了一个问题,

10块钱买啤酒,2块钱一瓶,2个空瓶或者4个瓶盖可以再换一瓶,问能买几瓶啤酒?

这个问题其实手算或者用Excel都挺容易的,不过这里用Mathematica来解决这个问题。代码很简单:

Bear[{钱_, 瓶盖_, 空瓶_, 啤酒总数_}] := 
 Module[{这次买到 = Floor[钱/2] + Floor[瓶盖/4] + Floor[空瓶/2]}, {Mod[钱, 2], 
   Mod[瓶盖, 4] + 这次买到, Mod[空瓶, 2] + 这次买到, 啤酒总数 + 这次买到}]

基本就是题目的翻版,输进去就能有答案:

In[2]:= Bear[{10, 0, 0, 0}]

Out[2]= {0, 5, 5, 5}

明显不对嘛,很简单啊,你这个问题是求不动点问题啊,所以正确的答案应该是

In[3]:= FixedPoint[Bear, {10, 0, 0, 0}]

Out[3]= {0, 3, 1, 15}

如果到这就结束了那该多无聊,所以我们就开始研究了。兑换过程是这样的:

In[4]:= FixedPointList[Bear, {10, 0, 0, 0}]

Out[4]= {{10, 0, 0, 0}, {0, 5, 5, 5}, {0, 4, 4, 8}, {0, 3, 3, 11}, {0,
   4, 2, 12}, {0, 2, 2, 14}, {0, 3, 1, 15}, {0, 3, 1, 15}}	

如果换成100个,答案是:

In[5]:= FixedPointList[Bear, {100, 0, 0, 0}]

Out[5]= {{100, 0, 0, 0}, {0, 50, 50, 50}, {0, 39, 37, 87}, {0, 30, 28,
   114}, {0, 23, 21, 135}, {0, 18, 16, 150}, {0, 14, 12, 162}, {0, 11,
   9, 171}, {0, 9, 7, 177}, {0, 6, 6, 182}, {0, 6, 4, 186}, {0, 5, 3, 
  189}, {0, 3, 3, 191}, {0, 4, 2, 192}, {0, 2, 2, 194}, {0, 3, 1, 
  195}, {0, 3, 1, 195}}

继续扩展,啤酒个数和钱数的关系是咋样的?

假设是30块钱以内:

Plot[Last@FixedPoint[Bear, {x, 0, 0, 0}], {x, 0, 30}, 
 PlotPoints -> 200, GridLines -> Automatic, 
 GridLinesStyle -> Directive[Red, Dashed], PlotTheme -> "Web"]

你得到的是如下关系:

假设到10000块钱,那么将是:

其实大概你的啤酒数等于两倍的钱数,这个有解析解的啦,有兴趣去推导去,不过我不觉得能得到更多信息。

然后可以来看看你需要计算的次数,对于10块钱以内的情况是这样的:

Plot[Length@FixedPointList[Bear, {x, 0, 0, 0}] - 2, {x, 0, 10000}, 
 PlotPoints -> 200, GridLines -> Automatic, 
 GridLinesStyle -> Directive[Red, Dashed], PlotTheme -> "Web"]

增长到10000块的时候,情况是这样的:

次数显然和钱数大概是一个对数关系,不信你去推解析解啊,真的是近似对数的关系。所以你弄个Excel表格,迭代100次,对于正常的钱数,基本可以保证最后的结果已经收敛。最后祝大家玩得开心啦!

BTW,文章头上的图像是这个代码生成的:

Plot[{{Last@FixedPoint[Bear, {x, 0, 0, 0}], 
   Length@FixedPointList[Bear, {x, 0, 0, 0}] - 1}}, {x, 0, 10}, 
 PlotPoints -> 200, GridLines -> Automatic, 
 GridLinesStyle -> Directive[Red, Dashed], PlotTheme -> "Web"]
此文文长1836字,君不评论一二?
亲,给点评论吧!

展开本分类索引