赞
踩
原理:割绳子算法:每次都取最大值为总绳长的随机值,最后将其排序,计算每两个的差值,总差值即就是总绳子长度,但是割绳子算法算出来的金额可能会出现超出最大金额的值,那么就会需要使用平均算法。
平均算法(自己取的名字):将超过最大限定金额的值全部重新赋值,并将他们舍去的部分,随机分给最小的金额,并保证最小的金额加上一个值不超过最大值即可。
洗牌算法:最终要将排序的金额进行打乱。
开源是程序员的基本美德
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}元");
该算法由C#写成,更多交流请关注原文博客地址:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。