技术 思绪 摘录 旅行
很多场景算红包的要求:根本问题就是指定的钱,指定的个数,红包发完,钱不剩余,最小红包1分钱,最大也需要限制。

原理:割绳子算法:每次都取最大值为总绳长的随机值,最后将其排序,计算每两个的差值,总差值即就是总绳子长度,但是割绳子算法算出来的金额可能会出现超出最大金额的值,那么就会需要使用平均算法。
平均算法(自己取的名字):将超过最大限定金额的值全部重新赋值,并将他们舍去的部分,随机分给最小的金额,并保证最小的金额加上一个值不超过最大值即可。
洗牌算法:最终要将排序的金额进行打乱。

开源是程序员的基本美德

            int pp = 100;//元换算成分的比例

            int total =(int)((decimal)10 * pp);//红包总额 
            int num = 8;//红包个数
            int min = (int)((decimal)0.02 * pp);//红包不少于
            int max = (int)((decimal)2 * pp);//最大红包不超过 

            if (min <= 0 && min >= (total - max) / (num - 1))
            {
                Console.WriteLine($"红包最小值异常:{total}分{num}个红包,最小值必须大于0,且不能小余{(total - max) / (num - 1)/100f}");
                return;
            }
            if (num * min > total)
            {
                Console.WriteLine($"红包最小值异常:{total}分{num}个红包,红包最小值不能超过{total / num / 100f}");
                return;
            }
            if (num * max < total)
            {
                Console.WriteLine($"红包最大值异常:{total}分{num}个红包,红包最大值不能小余{total / num / 100f}");
                return;
            }
            if (max > total - min * (num - 1))
            {
                Console.WriteLine($"红包最大值异常:{total}分{num}个红包,红包最大值不能超过{(total - min * (num - 1)) / 100f}");
                return;
            }

            float[] ret = new float[num];
            ret[0] = 0;
            int i = 1;
            //下面不考虑随机数的唯一性,给每个人都预留最少的钱
            int totalByHundred = total - (num * min);
            Random random = new Random();
            while (i < num)
            {
                ret[i] = random.Next(totalByHundred);
                i++;
            }
            //先从大到小排序  将差值计算出来+最先预留的min值
            Array.Sort(ret);
            i = 0;
            while (i < num - 1)
            {
                ret[i] = (ret[i + 1] - ret[i] + min);//每个人都预留最少的钱
                i++;
            }
            ret[i] = (totalByHundred - ret[i] + min);//最后一个 仍然是最大可分值-自身+min值即可。
            //再次排序金额  将超出最大值的金额 全部重新赋值,并将差值累加给tempmax ,然后将tempmax再依次随机分给最小的金额
            Array.Sort(ret);
            float tempmax = 0;
            for (int k = ret.Length - 1; k >= 0; k--)
            {
                if (ret[k] > max)
                {
                    float t = random.Next(min,max);
                    tempmax += ret[k] - t;
                    ret[k] = t;
                }
                else
                {
                    break;
                }
            }
            //分完为止  可能运气好  没有可分的 
            while (tempmax > 0)
            {
                Console.WriteLine("触发平均算法执行");
                Array.Sort(ret);
                for (int k = 0; k < ret.Length; k++)
                {
                    //一轮分不完  将再次排序再分  tempmax为0即可
                    if (tempmax > 0)
                    {
                        int tm = max - (int)ret[k];
                        if (tempmax< tm)
                        {
                            //此处判断非常重要 
                            ret[k] = ret[k] + tempmax;
                            tempmax = 0;
                        }
                        else
                        {
                            float t = random.Next(tm);
                            ret[k] = ret[k] + t;
                            tempmax -= t;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            //最后利用洗牌算法进行打乱数组
            int currentIndex;
            float tempValue;
            for (int j = 0; j < ret.Length; j++)
            {
                currentIndex = random.Next(0, ret.Length - j);
                tempValue = ret[currentIndex];
                ret[currentIndex] = ret[ret.Length -1- j];
                ret[ret.Length-1 - j] = tempValue;
            }
            //完美
            for (int j = 0; j < ret.Length; j++)
            {
                Console.WriteLine($"第{j + 1}个红包:金额{(ret[j] / 100f)}元");
            }
            //最后检查总红包金额以及最大最小红包是否符合要求  肯定符合要求的  只是输出看一下
            Console.WriteLine($"红包总金额:{(ret.Sum() / 100f).ToString("F2")}元,红包最大值:{ret.Max() / 100f}元,红包最小值:{ret.Min() / 100f}元");


CarsonIT 微信扫码关注公众号 策略、创意、技术

留下您的脚步

 

最近评论

查看更多>>

友情打赏

请打开您的微信,扫一扫