您的位置:首页 > 其它

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

2008-11-06 10:30 1246 查看
问题帖子:

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

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

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

我的回复:

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

public static void Main()
{
int count = 0;
// KEY-1:这里引入一些变量,减少递归次数
int _CNY1Sum = 0, _CNY2Sum = 0, _CNY5Sum = 0;
int _CNY10Sum = 0, _CNY20Sum = 0, _CNY50Sum = 0;
int _CNY100Sum = 0;
int Total = 0;
int Limit = 100;
Array<int> distribution[] = { 0, 0, 0, 0, 0, 0 };

//1元组成的情况,最多有100种
for (int a = 0; a <= 100; a++)
{
// initial each round
ResetDistribution(distribution, distribution.size);
// improvement
Total = 0;
_CNY1Sum = 1 * a;
distribution[0] = a;
Total = _CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); continue; }
if (Total > Limit) { break; }
//2元的情况,最多有50种可能
for (int b = 0; b <= 50; b++)
{
// improvement
_CNY2Sum = 2 * b;
distribution[1] = b;
Total = _CNY2Sum + _CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); break; }
if (Total > Limit) { break; }
//5元的情况,最多有20中可能
for (int c = 0; c <= 20; c++)
{
// improvement
_CNY5Sum = 5 * c;
distribution[2] = c;
Total = _CNY5Sum + _CNY2Sum + CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); break; }
if (Total > Limit) { break; }
//10元的情况,最多10种可能
for (int d = 0; d <= 10; d++)
{
// improvement
_CNY10Sum = 10 * d;
distribution[3] = d;
Total = _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); break; }
if (Total > Limit) { break; }
//20元的情况,最多5种可能
for (int e = 0; e <= 5; e++)
{
// improvement
_CNY20Sum = 20 * e;
distribution[4] = e;
Total = _CNY20Sum + _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); break; }
if (Total > Limit) { break; }
//50元的情况,最多2种可能
for (int f = 0; f <= 2; f++)
{
// improvement
_CNY50Sum = 50 * f;
distribution[5] = f;
Total = _CNY50Sum + _CNY20Sum + _CNY10Sum + _CNY5Sum + _CNY2Sum + _CNY1Sum;
if (Total == Limit) { count++; PrintSequence(distribution); break; }
if (Total > Limit) { break; }
}
}
}
}
}
}
Console.WriteLine("共有{0}种可能情况", count);
}

// new methods
private void ResetDistribution(Array<int> myZone, int mySize)
{ for (int i = 0; i < mySize; i++) myZone[i] = 0 }

private void PrintSequence(Array<int> myZone)
{
Console.WriteLine("Possible Solution for CNY100: " + myZone[0] + "   "
+ myZone[1] + "   " + myZone[2] + "   " + myZone[3]
+ "   " + myZone[3] + "   " + myZone[4] + "   " + myZone[5]);
}

/*
* Author: Leemax Li
* Created: 2008.11.05
* MSN: leemax@live.com
*
*/


------------------------------------ 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升的,有人拿着5、10、20升的,

* 大家都排队接水,那么如何可以使得整体时间最短?答案是按照从小

* 到大的顺序大家重新排队这样整体时间最短。(这是理想情况,但事

* 实上人作为感情动物,是不可能会这样重新排队的)

*

* 因此,如果按照面值从【大】到【小】的顺序循环,那么除了完整的

* 执行一次 100 × 50 × 20 × 10 ×5 × 2 的循环,找一些机制

* (improvement)就可以使得时间进一步缩短。

*

* 注意:因为是从最内圈开始数的,所以“先接水”的人应该在最内圈。

*

* 91楼的代码是按照1.2.5.10.20.50的结构写的~但如果按照50.20.10.5.2.1

* 的顺序循环,那么第一次的1元钱我们可以知道只需要循环15次(之前

* 已经有85元钱了),第二次13次…………但这时判断终止条件又不一样了,

* 需要新的条件,欢迎高手探讨一下。

*/

PS:如果是按照“接水”这种规划,似乎用点GoTo语句加上一些在for()括号外的++行为似乎可以达到这种效果?是不是会更接近AI?哈哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐