找零算法

说到算法,可能很多人都会和笔者一样有种晦涩艰深望而却步之感(当然对于那些灰常聪明精于算法的童鞋又另当别论)。在我们向技术高峰攀登的时候,处处都有算法这只传说中的技术老虎的身影,有时它还会突然跳出来挑战一下我们脆弱的小心脏。但是本篇介绍的这个灰常简单,曾经是某对日外包公司的笔试题。笔者甚至不知它能不能被称之为“算法”,请不要皱眉,看看不会妨碍您阅读的心情的。

一、问题还原
商场买东西的时候,营业员需要找零。现在有面额为100元、50元、20元、10元、5元、2元、1元、5角、2角、1角,5分,2分和1分的人民币若干,问,如何找零才能使现金最优发放(也就是说同一找零金额下,找零发放的人民币数量最少)。

二、经典解法
实现如下:

代码
  class Program
    {
        
//人民币面额
        private static decimal[] moneyArr = new decimal[] { 100M, 50M, 20M, 10M, 5M, 2M, 1M, 0.5M0.2M0.1M0.05M0.02M0.01M };
        
//存各种面额的人民币发放份数
        private static int[] moneyCountList = null;

        
static void Main(string[] args)
        {
            
decimal currentMoney = 188.88M;
            
int[] moneyCount = Calculate(currentMoney);
            Console.WriteLine(
"当前需找零金额:{0}¥", currentMoney);
            
for (int i = 0; i < moneyCount.Length; i++)
                Console.WriteLine(
"面额{0}¥ 共 {1} 张", moneyArr[i], moneyCount[i]);
            Console.ReadLine();
        }

        
/// <summary>
        
/// 计算发放金额数
        
/// </summary>
        
/// <param name="money"></param>
        
/// <returns></returns>
        static int[] Calculate(decimal money)
        {
            moneyCountList 
= new int[] { 0000000000000 };
            
int tmpMoney = NumHelper(money);
            
while (tmpMoney > 0)
            {
                
for (int i = 0; i < moneyArr.Length; i++)
                {
                    
if (tmpMoney >= NumHelper(moneyArr[i]))
                    {
                        tmpMoney 
-= NumHelper(moneyArr[i]); //减去一份发放的面额
                        moneyCountList[i] += 1;//对应的发送份数+1
                        break;
                    }
                }
            }
            
return moneyCountList;
        }

        
/// <summary>
        
/// 将金钱转换成整数处理
        
/// </summary>
        
/// <param name="money"></param>
        
/// <returns></returns>
        static int NumHelper(decimal money)
        {
            
return Convert.ToInt32(money * 100);
        }
    }

如你所看到的那样,简单的加减法就可以算出来。这实际上就是我们小时候数学课上做过的按照面额的从大到小进行“穷举”。
当然你可能会说加减没有乘除来的快,我们稍作改进:

代码
 class Program
    {
        
//人民币面额
        private static decimal[] moneyArr = new decimal[] { 100M, 50M, 20M, 10M, 5M, 2M, 1M, 0.5M0.2M0.1M0.05M0.02M0.01M };
        
//存各种面额的人民币发放份数
        private static int[] moneyCountList = null;

        
static void Main(string[] args)
        {
            
decimal currentMoney = 188.88M;
            
int[] moneyCount = Calculate(currentMoney);
            Console.WriteLine(
"当前需找零金额:{0}¥", currentMoney);
            
for (int i = 0; i < moneyCount.Length; i++)
                Console.WriteLine(
"面额{0}¥ 共 {1} 张", moneyArr[i], moneyCount[i]);
            Console.ReadLine();
        }

        
/// <summary>
        
/// 计算发放金额数
        
/// </summary>
        
/// <param name="money"></param>
        
/// <returns></returns>
        static int[] Calculate(decimal money)
        {
            moneyCountList 
= new int[] { 0000000000000 };
            
int tmpMoney = NumHelper(money);
            
while (tmpMoney > 0)
            {
                
for (int i = 0; i < moneyArr.Length; i++)
                {
                    
if (tmpMoney >= NumHelper(moneyArr[i]))
                    {
                        
int result = tmpMoney / NumHelper(moneyArr[i]); //直接除,比一条一条减算的快
                        moneyCountList[i] 
= result;//对应的发送份数
                        tmpMoney = tmpMoney % NumHelper(moneyArr[i]); //余数
                        break;
                    }
                }
            }
            
return moneyCountList;
        }

        
/// <summary>
        
/// 将金钱转换成整数处理
        
/// </summary>
        
/// <param name="money"></param>
        
/// <returns></returns>
        static int NumHelper(decimal money)
        {
            
return Convert.ToInt32(money * 100);
        }
    }

其实这就是一个简单数学问题的计算机语言(c#)描述而已(当然,您可能已经看出来了,上面的两段小程序写得一点也不OO。有心的读者也可以练练手试试看写一下对找零算法的OO改进版,期待指教),以前我们都是用c语言来描述的。说到这里,笔者不无沉重地又在脑袋里浮现起大学求学阶段某秃顶老头教算法和数据结构的课堂。当年某老人每次开始上课必然坚持来5分钟演讲,兴致勃勃地细说自己是如何依靠聪明才智和刻苦努力成功解决和征服算法的,说的好像天下所有算法都经过他老人家之手一样。同学们纷纷感叹,自恋的人常有,而像老头这么一上课就自恋的人不常有。通常老头的课上不到15分钟,台下就会有大面积异兆出现,比如交头接耳自说自话的,化蝶去见周公的,恩爱有加打情骂俏的......有时在他和蔼的逼视下,讲台下会适当有所收敛。总之一句话,你无法形容老头的课是多么的优秀。学院计系和信息系很多人都灰常庆幸地表示,上他老人家的课,他们得到了充足的休息和睡眠,所以下一学年,他们奋不顾身毅然决然地选择重修老头的课......时光匆匆,历历在目。农历虎年要到了,但是什么时候笔者才敢对算法大声说“I老虎U”呢?

ps:这应该是今年春节前的最后一篇,来年笔者会力争多写博客,多记录自己的开发心得,和大家共同提高。衷心恭祝各位博客园园友们在新的一年里一帆风顺,一往无前,百尺竿头更进一步,一如既往的健康快乐。

 

posted on 2010-02-07 17:48  JeffWong  阅读(3141)  评论(0编辑  收藏  举报