很多场景算红包的要求:根本问题就是指定的钱,指定的个数,红包发完,钱不剩余,最小红包1分钱,最大也需要限制。
开源是程序员的基本美德
1 int pp = 100;//元换算成分的比例 2 3 int total =(int)((decimal)10 * pp);//红包总额 4 int num = 8;//红包个数 5 int min = (int)((decimal)0.02 * pp);//红包不少于 6 int max = (int)((decimal)2 * pp);//最大红包不超过 7 8 if (min <= 0 && min >= (total - max) / (num - 1)) 9 { 10 Console.WriteLine($"红包最小值异常:{total}分{num}个红包,最小值必须大于0,且不能小余{(total - max) / (num - 1)/100f}"); 11 return; 12 } 13 if (num * min > total) 14 { 15 Console.WriteLine($"红包最小值异常:{total}分{num}个红包,红包最小值不能超过{total / num / 100f}"); 16 return; 17 } 18 if (num * max < total) 19 { 20 Console.WriteLine($"红包最大值异常:{total}分{num}个红包,红包最大值不能小余{total / num / 100f}"); 21 return; 22 } 23 if (max > total - min * (num - 1)) 24 { 25 Console.WriteLine($"红包最大值异常:{total}分{num}个红包,红包最大值不能超过{(total - min * (num - 1)) / 100f}"); 26 return; 27 } 28 29 float[] ret = new float[num]; 30 ret[0] = 0; 31 int i = 1; 32 //下面不考虑随机数的唯一性,给每个人都预留最少的钱 33 int totalByHundred = total - (num * min); 34 Random random = new Random(); 35 while (i < num) 36 { 37 ret[i] = random.Next(totalByHundred); 38 i++; 39 } 40 //先从大到小排序 将差值计算出来+最先预留的min值 41 Array.Sort(ret); 42 i = 0; 43 while (i < num - 1) 44 { 45 ret[i] = (ret[i + 1] - ret[i] + min);//每个人都预留最少的钱 46 i++; 47 } 48 ret[i] = (totalByHundred - ret[i] + min);//最后一个 仍然是最大可分值-自身+min值即可。 49 //再次排序金额 将超出最大值的金额 全部重新赋值,并将差值累加给tempmax ,然后将tempmax再依次随机分给最小的金额 50 Array.Sort(ret); 51 float tempmax = 0; 52 for (int k = ret.Length - 1; k >= 0; k--) 53 { 54 if (ret[k] > max) 55 { 56 float t = random.Next(min,max); 57 tempmax += ret[k] - t; 58 ret[k] = t; 59 } 60 else 61 { 62 break; 63 } 64 } 65 //分完为止 可能运气好 没有可分的 66 while (tempmax > 0) 67 { 68 Console.WriteLine("触发平均算法执行"); 69 Array.Sort(ret); 70 for (int k = 0; k < ret.Length; k++) 71 { 72 //一轮分不完 将再次排序再分 tempmax为0即可 73 if (tempmax > 0) 74 { 75 int tm = max - (int)ret[k]; 76 if (tempmax< tm) 77 { 78 //此处判断非常重要 79 ret[k] = ret[k] + tempmax; 80 tempmax = 0; 81 } 82 else 83 { 84 float t = random.Next(tm); 85 ret[k] = ret[k] + t; 86 tempmax -= t; 87 } 88 } 89 else 90 { 91 break; 92 } 93 } 94 } 95 96 //最后利用洗牌算法进行打乱数组 97 int currentIndex; 98 float tempValue; 99 for (int j = 0; j < ret.Length; j++) 100 { 101 currentIndex = random.Next(0, ret.Length - j); 102 tempValue = ret[currentIndex]; 103 ret[currentIndex] = ret[ret.Length -1- j]; 104 ret[ret.Length-1 - j] = tempValue; 105 } 106 //完美 107 for (int j = 0; j < ret.Length; j++) 108 { 109 Console.WriteLine($"第{j + 1}个红包:金额{(ret[j] / 100f)}元"); 110 } 111 //最后检查总红包金额以及最大最小红包是否符合要求 肯定符合要求的 只是输出看一下 112 Console.WriteLine($"红包总金额:{(ret.Sum() / 100f).ToString("F2")}元,红包最大值:{ret.Max() / 100f}元,红包最小值:{ret.Min() / 100f}元");
该算法由C#写成,更多交流请关注原文博客地址: