换啤酒问题

近日微信上有人传防痴呆问题:

2块钱买一瓶啤酒,四个瓶盖可以换一瓶啤酒,两个空瓶可以换一瓶啤酒,十块钱共能喝几瓶啤酒?

这个问题如果心算,如果就直肠子贪心法算的话,主要看记忆力。一般能心算出结果和零头的属于记忆力不错的,年轻人也不一定行。

如果在纸上算,只要不是太粗心的人,都能算出结果。但是学过一定数学的人,都怕这不是最优的结果。

其实假设单一解,贪心地算,这样一道题,结果很简单就是能喝15瓶酒,余下1个空瓶和三个瓶盖。但是如果我们列方程根据这些物品的价值来算,设啤酒价值为a,酒瓶价值为b,瓶盖价值为c,显然方程就是这样:

2¥ = a+b+c
2b = a+b+c
4c = a+b+c

很容易解出:

a = 0.5¥, b = 1¥, c = 0.5¥

这样,如果理想兑换的话(酒瓶和瓶盖能直接折算成钱/酒),10块钱能喝二十瓶啤酒,但这违反了题设的商业模式,显然无法做到。(但如果允许退款,是可以做到的,也是这道题目原题的答案)

貌似最优情况,也至少是要余下一个空瓶和一个瓶盖,但这也是不可能的。这个在数学结构上能够证明(从数学上应该能论证余b+2c和b+c是不可能的),也能用程序进行穷举证明,程序(穷举递归)如下:

  1 using System;
  2 
  3 namespace beers
  4 {
  5     class Program
  6     {
  7         class Asset
  8         {
  9             public Asset(int dollars)
 10             {
 11                 Dollars = dollars;
 12             }
 13 
 14             public Asset(Asset other)
 15             {
 16                 Beers = other.Beers;
 17                 Dollars = other.Dollars;
 18                 Bottles = other.Bottles;
 19                 Caps = other.Caps;
 20                 Record = other.Record;
 21             }
 22 
 23             public int Beers;
 24             public int Dollars;
 25             public int Bottles;
 26             public int Caps;
 27 
 28             // TODO string builder? it's just a tiny puzzle, don't worry about it
 29             public string Record;
 30 
 31             public bool ConsumeDollars()
 32             {
 33                 if (Dollars >= 2)
 34                 {
 35                     Dollars -= 2;
 36                     Beers++;
 37                     Bottles++;
 38                     Caps++;
 39                     Record += string.Format("use 2 dollars\n");
 40                     return true;
 41                 }
 42                 return false;
 43             }
 44 
 45             public bool ConsumeBottles()
 46             {
 47                 if (Bottles >= 2)
 48                 {
 49                     Bottles -= 2;
 50                     Beers++;
 51                     Bottles++;
 52                     Caps++;
 53                     Record += string.Format("use 2 bottles\n");
 54                     return true;
 55                 }
 56                 return false;
 57             }
 58 
 59             public bool ConsumeCaps()
 60             {
 61                 if (Caps >= 4)
 62                 {
 63                     Caps -= 4;
 64                     Beers++;
 65                     Bottles++;
 66                     Caps++;
 67                     Record += string.Format("use 4 caps\n");
 68                     return true;
 69                 }
 70                 return false;
 71             }
 72         }
 73 
 74         static Asset Solve(Asset input)
 75         {
 76             var o1 = new Asset(input);
 77             o1 = o1.ConsumeDollars() ? Solve(o1) : null;
 78 
 79             var o2 = new Asset(input);
 80             o2 = o2.ConsumeBottles() ? Solve(o2) : null;
 81 
 82             var o3 = new Asset(input);
 83             o3 = o3.ConsumeCaps() ? Solve(o3) : null;
 84 
 85             if (o1 != null && (o2 == null || o1.Beers > o2.Beers) && (o3 == null || o1.Beers > o3.Beers))
 86             {
 87                 return o1;
 88             }
 89 
 90             if (o2 != null && (o3 == null || o2.Beers > o3.Beers))
 91             {
 92                 return o2;
 93             }
 94 
 95             if (o3 != null)
 96             {
 97                 return o3;
 98             }
 99 
100             return input;
101         }
102 
103         static void Main(string[] args)
104         {
105             var ini = new Asset(10);
106             var opt = Solve(ini);
107             Console.WriteLine("result: {0} beers + {1} bottles {2} caps", opt.Beers, opt.Bottles, opt.Caps);
108             Console.WriteLine("process:\n{0}", opt.Record);
109         }
110     }
111 }

 

posted @ 2015-10-22 19:06  quanben  阅读(1747)  评论(0编辑  收藏  举报