目前项目中遇到一个问题,大致描述就是给出一个总数,然后设置一个范围区间,在范围区间内取随机值,最后相加等于给出的总数
咋一看好像挺简单的,但做的时候发现有很多坑,因此在这里做个记录和总结。因为源代码是计算金额的,因此变量设为了decimal。
这边先做好定义,设输入的总数为total,范围定义为[min,max]
首先,根据输入的数据的不同,这个问题是有绝对无法得出结果的情况的。当 min和max同时乘一个整数,如果total不在这个区间内,即 total % min + min > max 时,根本无法得出答案。
举个例子就是 区间为 5500-6000,分别乘2为11000-12000,在total为6000-11000区间内(不含边界)时,永远无法得出结果。同理,直到 5500 / (6000-5500) * 5500 之后,才能保证所有数都得出结果。
ps:因为算法原因,边界值出现的概率还是比较大的(特别是数据少时),这点可以看代码自己体会。
if(total % min + min > max) { throw new Exception("当前选项无法计算出结果"); } int length= (int)Math.Floor(total / min); //数组的最大长度,循环的次数,不代表最终长度 List<decimal> salary = new List<decimal>(); //最终的数组for (int i = 0; i < length; i++) { if (total >= min && total <= max) //剩下的值刚好在范围内,退出循环 { salary.Add(total); total = 0; break; } else if(total < min) //剩下的值 < 下限 { for (int j = 0; j < salary.Count; j++) //循环已经生成的列表,依次给上剩余的值 { if(salary[j] + total > max) //相加 > 上限 { total = salary[j] + total - max; //调整total值 salary[j] = max; //调整为上限 } else //相加 <= 上限则加上,并退出循环 { salary[j] += total; total = 0; break; } } if(total > 0) //如果上一步循环给完还是有剩余,应为此时已经循环完所有的项,就只能再增加一个数据,并减少前面的项分给最后一个 { decimal dis = min - total; //其他数需要减去的差值 salary.Add(min); for (int j = 0; j < salary.Count - 1; j++) { if(salary[j] - dis < min) //不够减 { dis = dis - salary[j] + min; //调整dis salary[j] = min; } else //够减,退出循环 { salary[j] -= dis; dis = 0; break; } } } break; } decimal wage = new Random().Next(min, max); salary.Add(wage); total -= wage; }
c#实现给定总数和范围区间,随机生成和等于这个总数的数组或列表
原文:https://www.cnblogs.com/kusaki/p/14514603.html