TOPCODER->Practice Room->SRAM 144 DIV 1 (550)

问题描述

  在大多数国家,有大量不同的彩票游戏供投机者选择。彩票的规则由两个整数(choices和blanks)及两个布尔型变量(sorted和unique)定义。choices代表你可以使用在你的彩票上的最高有效数。(所有在1到choices之间的整数,包括choices,是有效数并可以使用在你的彩票上。)blanks代表你可以插入的数字的数量。
  sorted和unique变量表明你可创建的彩票的限制条件。若sorted被设为true,那么彩票上的数字必须被写为非降序的。若sorted被设为false,那么彩票上就可以任意写。同样的,若unique被设为true,那么你所写的数字都必须是唯一的。若unique被设为false,那就可以写重复数了。
  下面有几个彩票的示例,其中choices=15然后blanks=4:

    {3,7,12,14} -- 这个彩票绝对是可以的。
    {13,4,1,9} -- 因为这组数字并不是顺序的,所以必须是sorted=false才合法。
    {8,8,8,15} -- 因为有数字重复,所以必须当unique=false时才合法。
    {11,6,2,6} -- 这组数字必须当sorted=false且unique=false时才合法。

  给你一列彩票和对应的规则,返回一列彩票的名字并以获胜的难易程度来排序。获胜的几率=(1/合法的彩票数量)。最容易获胜的彩票需要出现在列表的最前面。Ties should be broken alphabetically

定义

  Class:        Lottery
  Method:       sortByOdds
  Parameters:     String[]
  Returns:       String[]
  Method signature:  String[] sortByOdds(String[] rules)
  (确定你的method是public)

约束

  - 规则将包含0到50个元素,包括0和50.
  - 每一个规则元素将包含11到50个字符,包括11和50
  - 所有规则元素将按这样的格式"<NAME>:_<CHOICES>_<BLANKS>_<SORTED>_<UNIQUE>"(quotes for clarity)。下划线代表一个空格。
  - <NAME>包含1到40个字符,包括1和40,而且仅由大写字母('A'-'Z')和空格(' ')组成,前后均无空格。
  - <CHOICES>是10到100的整数,包括10和100,最前面没有0。
  - <BLANKS>是1到8的整数,包括1和8,最前面没有0。
  - <SORTED>会是'T'(true)或'F'(false)中的一个。
  - <UNIQUE>会是'T'(true)或'F'(false)中的一个。
  - 规则里没有重名的元素

例子

  0)

    {"PICK ANY TWO: 10 2 F F"
    ,"PICK TWO IN ORDER: 10 2 T F"
    ,"PICK TWO DIFFERENT: 10 2 F T"
    ,"PICK TWO LIMITED: 10 2 T T"}

    返回:
    { "PICK TWO LIMITED",
      "PICK TWO IN ORDER",
      "PICK TWO DIFFERENT",
      "PICK ANY TWO" }

    "PICK ANY TWO"中所有空格可以是1到10的数字。那么,就会有10*10种可能的彩票,所以你赢的概率为1/100
    "PICK TWO IN ORDER"显示第一个数字不能比第二个数字更大。这就排除了45种可能性,只剩下55种合法彩票。那么赢得概率就是1/55.
    "PICK TWO DIFFERENT"只是不允许彩票中第一个数字和第二个数字一样。这里有10个这样的彩票,那么赢得概率就变为1/90。
    最后,"PICK TWO LIMITED"在"PICK TWO IN ORDER"不允许的45个彩票的基础上又增加了另外10个。所以现在概率变为1/45。

  1)

    {"INDIGO: 93 8 T F",
     "ORANGE: 29 8 F T",
     "VIOLET: 76 6 F F",
     "BLUE: 100 8 T T",
     "RED: 99 8 T T",
     "GREEN: 78 6 F T",
     "YELLOW: 75 6 F F"}

    返回:
    Returns: { "RED",  "ORANGE",  "YELLOW",  "GREEN",  "BLUE",  "INDIGO",  "VIOLET" }

    需要注意:INDIGO和BLUE是同样的概率(1/186087894300)。按字母排序,所以BLUE在INDIGO前面。

  2)

    {}

    返回:
    { }

    为空的情况

解析

  1 规则

    choices  最高有效数  1到choices
    blanks  有效数个数
    sorted  是否降序    true必须升序  false无限制
    unique  是否必须唯一  true必须唯一  false无限制

  2 计算方法

    这实际上是一个排序问题(参考人教版新课标选修2-3,1.2节排列与组合 http://www.gaokao.com/zyk/dzkb/sxkb/rxsx2_3/)

    1)sorted=false;unique=true

      从m个不同元素中,抽取n个元素的排列,不可重复,无需顺序排列。
      结果:A(m,n)

    2)sorted=true;unique=true

      从m个不同元素中,抽取n个元素的排列,不可重复,需顺序排列。
      结果:C(m,n)

    3)sorted=false;unique=false

      从m个不同元素中,抽取n个元素的排列,可重复,无需顺序排列。
      分析:
        n个空格的中的任意一个,可抽取的元素个数都为m,故其排列共有:n个m相乘
      结果:
        m^n

    4)sorted=true;unique=false

      从m个不同元素中,抽取n个元素的排列,可重复,需顺序排列。
      结果:C(m+n-1,n)
      (说不清楚为什么。。。)

Choices

Blanks

Sorted

Unique

计算公式

m

n

False

False

m^n

m

n

False

True

A(m,n)

m

n

True

False

C(m+n-1,n)

m

n

True

True

C(m,n)

 

 

 

 

 

 

 

 

    注1:A(m,n)=m*(m-1)*(m-2).....(m-n+1), 如A(4,3)=4*3*2
    注2:C(m,n)=A(m,n)/A(n,n),如C(4,3)=4*3*2/3*2*1 

  3 边界

    从原文中我们知道m始终大于n,故不用考虑边界问题。

解答

  1 实现A(m,n)

        //A(m,n)未考虑边界问题
        public int Arrangement(int m,int n)
        {
            int result = 1;
            for (int i = 0; i < n; i++)
            {
                result = result * m;
                m = m - 1;
            }
            return result;
        }

  2 实现C(m,n)

        //C(m,n)=A(m,n)/A(n,n)
        public int Combination(int m, int n)
        {
            int result = 1;
            result = Arrangement(m, n) / Arrangement(n, n);
            return result;
        }

  3 实现m^n

        //m^n
        public int PowerOf(int m, int n)
        {
            int result = 1;
            for (int i = 0; i < n; i++)
            {
                result = result * m;
            }
            return result;
        }

  4 根据规则计算出排列组合数

        //根据规则计算出排列组合数
        public int Analysis(string rule)
        {
            string[] term;
            term = Detach(rule);    //使用正则表达式将规则分拆
            int m = int.Parse(term[0]);
            int n = int.Parse(term[1]);
            string sorted = term[2];
            string unique = term[3];

            if ( sorted == "F" && unique == "F")
            {
                //m^n
                return PowerOf(m, n);
            }
            if (sorted == "F" && unique == "T")
            {
                //A(m,n)
                return Arrangement(m, n);
            }
            if (sorted == "T" && unique == "F")
            {
                //C(m+n-1,n)
                return Combination(m + n - 1, n);
            }
            if (sorted == "T" && unique == "T")
            {
                //C(m,n)
                return Combination(m, n);
            }
            return 0;
        }

        //使用正则表达式将规则分拆
        public string[] Detach(string rule)
        {
            string[] result = new string[4];
            MatchCollection mc;
            Regex r = new Regex("\\w{1,3}");
            mc = r.Matches(rule);
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = mc[i].ToString();
            }
            return result;
        }

  5 将rules的规则按条解开

        //将rules中的规则按条解开
        public string[] sortByOdds(string[] rules)
        {
            string[] result1 = new string[0];
            List<string[]> resultList = new List<string[]>();
            string[] oneRule;
            if (rules == null || rules.Length <= 0)
            {
                //result[0] = " ";
                return result1;
            }

            for (int i = 0; i < rules.Length; i++)
            {
                oneRule = Cut(rules[i]);//将规则名和规则内容切开
                oneRule[1] = Analysis(oneRule[1]).ToString();//将规则转换为组合数
                resultList.Add(oneRule);//保存解析后的结果
            }

            //使用冒泡法对结果进行排序
            resultList = Sort(resultList);
            //保存结果
            string[] result2 = new string[resultList.Count];
            for (int i = 0; i < resultList.Count; i++)
            {
                result2[i] = resultList[i][0];
            }
            return result2;
        }
        //使用冒泡法对结果进行排序
        public List<string[]> Sort(List<string[]> ruleList)
        {
            if (ruleList.Count<=1)
            {
                return ruleList;
            }
            //遍历list
            for (int i = 0; i < ruleList.Count-1; i++)
            {
                for (int j = i+1; j < ruleList.Count; j++)
                {
                    long ri = long.Parse(ruleList[i][1]);
                    long rj = long.Parse(ruleList[j][1]);

                    if (ri > rj)//将较小的数向前挪
                    {
                        string[] rule = new string[2];
                        rule = ruleList[j];
                        ruleList[j] = ruleList[i];
                        ruleList[i] = rule;
                    }
                    else if (ri == rj)//若两数一样大,则按首字母排序。若首字母也一样,则不动
                    {
                        char ci = ruleList[i][0][0];
                        char cj = ruleList[j][0][0];
                        if (ci > cj)
                        {
                            string[] rule = new string[2];
                            rule = ruleList[j];
                            ruleList[j] = ruleList[i];
                            ruleList[i] = rule;
                        }
                    }
                }
            }
            return ruleList;
        }

   6 将规则名和规则内容切开

        //将规则名和规则内容切开
        public string[] Cut(string rule)
        {
            string[] result = new string[2];
            int point = rule.IndexOf(':');
            result[0] = rule.Substring(0, point);//规则名
            result[1] = rule.Substring(point+1, rule.Length-point-1);//规则内容
            return result;
        }

 

 

 

 

 

 

posted @ 2013-02-21 10:53  布兰姥爷  阅读(537)  评论(0编辑  收藏  举报