用1元,2元,5元,10元,20元和50元的纸币组成100元,共有多少种情况

2 篇文章 0 订阅

问题帖子:

http://topic.csdn.net/u/20081016/14/8E1B21C7-DBC8-40CE-BA93-28C4CAC4E461.html

 

用1元,2元,5元,10元,20元和50元的纸币组成100元,共有多少种情况。
要求写出除了多重循环方案之外的另一种程序代码,要求输出总方案数和每种方案中各纸币的个数。

这个是原题,当然,如果你有循环的实现也可以贴上来。

 

我的回复:

我来解一些,就用最简单的循环。。本来想再写个递归。。。大同小异,累死我了,忽略~
递归方法:(整体结构copy自91楼,并改进之)

   
   
  1. public static void Main() 
  2.     int count = 0; 
  3.     // KEY-1:这里引入一些变量,减少递归次数
  4.     int _CNY1Sum = 0, _CNY2Sum = 0, _CNY5Sum = 0;
  5.     int _CNY10Sum = 0, _CNY20Sum = 0, _CNY50Sum = 0;
  6.     int _CNY100Sum = 0;
  7.     int Total = 0;
  8.     int Limit = 100;
  9.     Array<int> distribution[] = { 0, 0, 0, 0, 0, 0 };
  10.     //1元组成的情况,最多有100种 
  11.     for (int a = 0; a <= 100; a++) 
  12.     {
  13.         // initial each round
  14.         ResetDistribution(distribution, distribution.size);        
  15.         // improvement
  16.         Total = 0;
  17.         _CNY1Sum = 1 * a;
  18.         distribution[0] = a;
  19.         Total = _CNY1Sum;
  20.         if (Total == Limit) { count++; PrintSequence(distribution); continue; }
  21.         if (Total > Limit) { break; }
  22.         //2元的情况,最多有50种可能 
  23.         for (int b = 0; b <= 50; b++) 
  24.         {
  25.             // improvement
  26.             _CNY2Sum = 2 * b;
  27.             distribution[1] = b;
  28.             Total = _CNY2Sum + _CNY1Sum;
  29.             if (Total == Limit) { count++; PrintSequence(distribution); break; }
  30.             if (Total > Limit) { break; }
  31.             //5元的情况,最多有20中可能
  32.             for (int c = 0; c <= 20; c++) 
  33.             {
  34.                 // improvement
  35.                 _CNY5Sum = 5 * c;
  36.                 distribution[2] = c;
  37.                 Total = _CNY5Sum + _CNY2Sum + CNY1Sum;
  38.                 if (Total == Limit) { count++; PrintSequence(distribution); break; }
  39.                 if (Total > Limit) { break; }
  40.                 //10元的情况,最多10种可能 
  41.                 for (int d = 0; d <= 10; d++) 
  42.                 {
  43.                     // improvement
  44.                     _CNY10Sum = 10 * d;
  45.                     distribution[3] = d;
  46.                     Total = _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
  47.                     if (Total == Limit) { count++; PrintSequence(distribution); break; }
  48.                     if (Total > Limit) { break; }
  49.                     //20元的情况,最多5种可能 
  50.                     for (int e = 0; e <= 5; e++) 
  51.                     {
  52.                         // improvement
  53.                         _CNY20Sum = 20 * e;
  54.                         distribution[4] = e;
  55.                         Total = _CNY20Sum + _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
  56.                         if (Total == Limit) { count++; PrintSequence(distribution); break; }
  57.                         if (Total > Limit) { break; }
  58.                         //50元的情况,最多2种可能 
  59.                         for (int f = 0; f <= 2; f++) 
  60.                         {
  61.                             // improvement
  62.                             _CNY50Sum = 50 * f;
  63.                             distribution[5] = f;
  64.                             Total = _CNY50Sum + _CNY20Sum + _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
  65.                             if (Total == Limit) { count++; PrintSequence(distribution); break; }
  66.                             if (Total > Limit) { break; }
  67.                         } 
  68.                     } 
  69.                 } 
  70.             } 
  71.         } 
  72.     } 
  73.     Console.WriteLine("共有{0}种可能情况", count);          
  74. }
  75. // new methods
  76. private void ResetDistribution(Array<int> myZone, int mySize)
  77. for (int i = 0; i < mySize; i++) myZone[i] = 0 }
  78. private void PrintSequence(Array<int> myZone)
  79. {
  80.     Console.WriteLine("Possible Solution for CNY100: " + myZone[0] + "   "
  81.                       + myZone[1] + "   " + myZone[2] + "   " + myZone[3]
  82.                       + "   " + myZone[3] + "   " + myZone[4] + "   " + myZone[5]);
  83. }
  84. /*
  85.  * Author: Leemax Li
  86.  * Created: 2008.11.05
  87.  * MSN: leemax@live.com
  88.  * 
  89. */


------------------------------------  Analysis ------------------------------------

也许循环和递归不是最高效的方法,但却是最易懂的写法~而容易阅读的代码对于日后的维护也起着至关重要的作用。

也许有人可以写出更简洁的代码,但如果那简短高效代码却要花费别人1、2个小时去琢磨,那其实也不是什么好代码。

KISS: Keep It Simple Stupid~ remember?

但是,单纯的 100 × 50 × 20 × 10 ×5 × 2 粗暴的循环我个人觉得也是蛮“楞”的,所以综合计算机的高效和咱们人类的智慧,运用诸如统筹啊、线性规划啊(一堆乱七八糟的学术名词,用来提升自己的“表面”素质)等各种分析手段,我们可以发现:

当某次循环的等于或者大于限制时,接下来的循环就是完全没必要的。

也就是说:如果 99 张 1元钱了, 那么当我们进入 2 元钱的第一次循环时,不难发现 99 + 2 = 101 。。。这已经超出了题目要求,那必然两张2元钱或者再来一张5元钱更不可能符合范围要求,因此可以直接跳出循环(break)进入下一轮~

------------------------------------ Analysis ------------------------------------

  1. /*
  2.  * 另一种思路:有一个经典的例子,大家一定都听说过:
  3.  * 问,有人拿着1升的水桶,有人拿着2升的,有人拿着5、10、20升的,
  4.  * 大家都排队接水,那么如何可以使得整体时间最短?答案是按照从小
  5.  * 到大的顺序大家重新排队这样整体时间最短。(这是理想情况,但事
  6.  * 实上人作为感情动物,是不可能会这样重新排队的)
  7.  * 
  8.  * 因此,如果按照面值从【大】到【小】的顺序循环,那么除了完整的
  9.  * 执行一次 100 × 50 × 20 × 10 ×5 × 2 的循环,找一些机制
  10.  * (improvement)就可以使得时间进一步缩短。
  11.  * 
  12.  * 注意:因为是从最内圈开始数的,所以“先接水”的人应该在最内圈。
  13.  * 
  14.  * 91楼的代码是按照1.2.5.10.20.50的结构写的~但如果按照50.20.10.5.2.1
  15.  * 的顺序循环,那么第一次的1元钱我们可以知道只需要循环15次(之前
  16.  * 已经有85元钱了),第二次13次…………但这时判断终止条件又不一样了,
  17.  * 需要新的条件,欢迎高手探讨一下。
  18. */

 

 

PS:如果是按照“接水”这种规划,似乎用点GoTo语句加上一些在for()括号外的++行为似乎可以达到这种效果?是不是会更接近AI?哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值