お年玉のアルゴリズム

3254 ワード

需要
お年玉のアルゴリズムがあり、需要は全部で50000個で、金額は75000元で、お年玉ごとに1元から2元の間で要求されています.
インプリメンテーション
一時的な実装は異常チェックや最適化を考慮せず,コードを貼ってからにしよう.
             public static List RandomRedPacket(int packetCount, Decimal totalBonus, Decimal minBonus, Decimal maxBonus)
        {
            Random RandomEvent = new Random();
            List resultList = new List();

            for (int i = 0; i < packetCount; i++)
            {
                if (i == packetCount-1)
                {
                    resultList.Add(totalBonus);
                }
                else
                {
                    decimal thisBonus=0.00m;
                    //                   
                    decimal avgBonus = totalBonus / (packetCount - i);   
                    if (avgBonus > maxBonus)
                    {
                        //                 :1-2
                        thisBonus=RandomEvent.NextDecimal(minBonus, maxBonus ); 
                    }
                    else if (avgBonus < maxBonus && avgBonus>(maxBonus+minBonus)/2)
                    {
                        //                 :>1.5-2
                        thisBonus = RandomEvent.NextDecimal(avgBonus, maxBonus);   
                    }
                    else
                    {
                        //                 :1-<1.5
                        thisBonus = RandomEvent.NextDecimal(minBonus, avgBonus);
                    }
                    thisBonus = Math.Round(thisBonus, 2);
                    resultList.Add(thisBonus);
                    totalBonus -= thisBonus;
                }
            }
            return resultList;
        }

ここでRandomクラスにDecimalを取得する方法を拡張します.
        public static decimal NextDecimal(this Random rnd, decimal from, decimal to)
        {
            byte fromScale = new System.Data.SqlTypes.SqlDecimal(from).Scale;
            byte toScale = new System.Data.SqlTypes.SqlDecimal(to).Scale;

            byte scale = (byte)(fromScale + toScale);
            if (scale > 28)
                scale = 28;

            decimal r = new decimal(rnd.Next(), rnd.Next(), rnd.Next(), false, scale);
            if (Math.Sign(from) == Math.Sign(to) || from == 0 || to == 0)
                return decimal.Remainder(r, to - from) + from;

            bool getFromNegativeRange = (double)from + rnd.NextDouble() * ((double)to - (double)from) < 0;
            return getFromNegativeRange ? decimal.Remainder(r, -from) + from : decimal.Remainder(r, to);
        }

最終テストは次のとおりです.
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                List poker = RandomRedPacket(50, 75, 1.00m, 2.00m);
                Decimal total = poker.Sum();
                Console.WriteLine("          :" + total);
                Console.WriteLine("        1-2      :" + poker.TrueForAll(x => x >= 1 && x <= 2));
                Console.WriteLine("      :" + string.Join(",", poker.ToArray()));
            }
            Console.ReadLine();
        }