SRM练习题550Point解析之一:Lottery彩票

    本文是解析Top Coder的SRM练习题550Point系列的第一篇,Lottery彩票。

    问题描述是全英文的,由于英文水平有限,所以发了不少时间才完全看明白。本人觉得Top Coder的题目挺有趣的,激发着我的智慧去解决它。在这个过程中,自己解决实际问题的能力得到了提升,而且算法能力、编程基础也得到了巩固、加强。在此与大家一起分享,一起成长。

      TopCoder竞赛介绍http://www.wyu.cc/viewthread.php?tid=53252

    由于未授权,问题描述不能在此贴出,十分遗憾!获得原题请登录TopCoder Practice Room —1 SRMs—1-16—1 SRM 144 DIV1

解析:解决本题主要有两点:第一,如何把问题转化为数学模型,然后用数学知识解答;第二,应用多关键字排序的算法。

一、  转化为数学模型

       首先,从最简单的情况入手,第一种规则[102FF]表示此类彩票由任意两个1-10的数字组成,不需要按升序排序(任意序列),也可以出现相同的数字,如{12}{105}{44}都是有效的彩票。这是最简单的一种情况,按照排列的数学知识可以知道,这种规则彩票的有效个数是10*10=100个。更一般的规则为[maxcountFF],有效个数为maxcount次幂个,即max count。代码实现如下:

1Int64 result=(Int64)Math.Pow(max, count);//数据很大,有可能超过32位

 

       第二种规则[102FT]表示此类彩票由任意两个1-10的数字组成,数字系列任意排序,但是不能出现重复的。如{33}是无效的彩票,按照排列的知识可以知道,此类彩票的个数是10*9=90个。更一般的规则为[maxcountFF],有效个数为max*(max-1)*…*(max-count+1)个。代码实现如下:

1 Int64 result = 1;
2 for (int i = max; i >= max - count + 1; i--{
3     result *= i;
4 }

 

       第三种规则[102TF]表示此类彩票由任意两个1-10的数字组成,但是数字系列必须是按升序排序,可以重复出现。我们可以知道当第一个数字为1时,第二个数字可以是1-10,这10个数字;当第一个数字为2时,第二个数字可以是2-10,这9个数字,由此可以推出,当第一个数字为10时,第二个数字只可以为10,这1个数字。那么所有的符合规则有效的彩票个数为10+9+8+7+6+5+4+3+2+1个。

如果可以输入的数字为3个,即[103TF]时,同样的,当第一个数字为1时,后面的两个数字同[102TF]一样,有10+9+…+1种情形;当第1个数字为2时,后面的两个数字有9+8+…+1种情形。整个数学模型如下:

2个数字:     10+ 9 + 8 + 7 +6 + 5 +4 + 3 + 2 + 1

3个数字:(10+9+…+1+9+8++1+7+6++1++2+1+1  

4个数字:((10+9+1+9+8++1++1+((9+8++1++1++1

                              

一般的[maxcountTF]时为,领头的最大数字为max

可以看出每种情况都是由10个单元相加组成的和,而且当数字增加一个的时候,每个单元的值都是前一种情况下,它本身及其后面所有单元的和,这就是一种典型的迭代,代码实现如下:

Code

       第四种规则[102TT]表示此类彩票由任意两个1-10的数字组成,但是数字系列必须是按升序排序,而且不可以重复出现。我们可以知道当第一个数字为1时,第二个数字必须是2-10,这9个数字;当第一个数字为2时,第二个数字必须是3-10,这8个数字。同理可知符合规则有效的彩票个数为

9+8+7+6+5+4+3+2+1个。

如果可以输入的数字为3个,即[103TT]时,同样的有效的个数为

8+7+6+5+4+3+2+1+7+6+5+4+3+2+1++1

一般的[maxcountTT]时为领头的最大数字为max-count+1。代码实现同第三种规则。

二、  多关键字排序

       实现多关键字排序,有两种方法:第一种是,先对最主要的关键字排序,再对有相同最主要关键字值的子序列进行次关键字排序,依此类推,此方法称为Most Significant Digit First (MSD)法;第二种是,先对最次要的关键字进行全体排序,再对次要的关键字进行全体排序,依此类推,此方法称为最Least Significant Digit First LSD)法。

       MSD法和LSD法只是约定了“关键字的次序”来排序,但并未约定对每一个关键字使用的排序方法(如快速排序,插入排序等)。MSDLSD法的实现区别是:MSD法根据关键字次序对序列逐层进行分割成若干个子序列,再对子序列进行排序;LSD法不必分割成子序列,对每个关键字都是整个序列参加排序,但必须是定排序。

MSD的代码实现方法:

Code

 

LSD的代码实现方法:

由于在.NET类库中未找到现成的稳定排序算法,所以打算模仿Array.Sort使用的快速排序法,实现一个比较规范的稳定排序算法。等写完后,再来补充此实现。

三、  常用的FCL框架类库

       String类的Split方法

           返回由指定的字符或字符串数组分割此String实例而得到的子字符串数组。

       Array类的Sort方法

          此方法使用QuickSort快速排序算法,是不稳定排序算法。

       条件运算符xxx?xxx:xxx

            无嵌套if...else语句,使用条件运算符来代替还是比较简洁的。说真的,非常少用。

      伪随机数生成器Random类

            随机数的生成是从种子值开始,即构造函数的参数。建议只创建一个实例。如果重复创建默认实例,有可能产生相同的值,而非随机数。 

 四、 完整代码(略)

      感觉整个贴出来太啰嗦了,o(∩_∩)o...

posted on 2009-07-09 23:12  Sandwi  阅读(565)  评论(0编辑  收藏  举报

导航