如何把一个数字 x 随机分成 y 个数字,这些数字≥a 且≤b

2021-01-18 14:18:22 +08:00
 kaiki
类似发红包的算法,但是加了个最大值和最小值限制,自己写了一个感觉不太行,有没有简单的办法?
2394 次点击
所在节点    问与答
39 条回复
kiracyan
2021-01-18 14:35:49 +08:00
这样?
for(i= 0;i<y;i++){
var num = random(a,b)
x -= num
}
Glauben
2021-01-18 14:36:48 +08:00
直接生成[a,b]之间的随机数,从 X 中里扣除,循环 Y 次,最后一次直接用剩下的
kaiki
2021-01-18 14:38:36 +08:00
@2435043xia 如果每次随机到的数值都<(a+b)/2,剩下的就绝对超过 b 了啊
sillydaddy
2021-01-18 14:39:52 +08:00
在 0 ~ x 范围内,取 y-1 个随机数,将 x 划分成 y 段,从中取出一段,该段长度符合大于等于 0 小于等于 d ;
从 x 中减去已经取的段,迭代上面的过程,每次迭代时分段数目要减 1 。

把 a ~ b 的范围,转换成上面算法要求的 0 ~ d 即可。
kaiki
2021-01-18 14:41:00 +08:00
@kiracyan 要分完,我应该直接把数字带入的,x=100,y=10,a=5,b=15
这也随机取到 9 个 5,最后一个岂不是 55 了,大于 15 了
sillydaddy
2021-01-18 14:43:10 +08:00
@sillydaddy 我说的好像有问题。。不能保证所有段的和等于总和
chengfeng1992
2021-01-18 14:50:30 +08:00
首先判断 ( x >= a*y ) && (x <= b*y) 来确定有解

然后给每个值分最小值之后的余数 remainder = x - a*y

再然后把余数随机分成 y 份,其中最大值 max = b - a,最小值 min = 0,相当于把问题转化成了简单的红包算法

最后把分成的值分别+a 得到结果
sillydaddy
2021-01-18 14:55:28 +08:00
想了下,感觉这道题目应该叫,"约束空间范围的随机采样",就类似于要求在一个多边形内部,随机取一个点。

坐等高手。
XiaoxiaoPu
2021-01-18 14:58:09 +08:00
设第一个数字使 r1
1. 显然第一个数需要满足 a <= r1<= b
2. 为了使后面的分配仍能继续,需要满足 x - r1 >= (y-1) * a,x - r1 <= (y-1) * b,即 r1 >= x - (y - 1) * a,r1 <= x - (y - 1) * b
综合 1,2 得到 r1 的取值区间 [max(a, x - (y - 1) * a), min(b, x - (y - 1) * b)](如果无法得到此区间,说明问题无解),在此区间内随机取一个数,即得 r1 。

对于第二个数,转化为数字 x - r1 分成 y - 1 个数字,这些数字≥a 且≤b,同上可得 r2
sillydaddy
2021-01-18 14:59:36 +08:00
@chengfeng1992 取 max 的过程有点问题吧,感觉这样的话算法不是随机的了。类比我上面举的例子,给定一个 2d 上的多边形,要求在内部随机取点。这时如果先随机取 x,再根据 x 的值,在 x 对应的 y 范围内随机取 y,会导致结果不随机。
chenluo0429
2021-01-18 15:04:00 +08:00
你可以先想象一下,先给 y 个数字位置都分配 a,那么问题就变成了把数字(x -ya)随机分成 y 个数字,且这些数字满足[0, b - a]。
Stoulla
2021-01-18 15:04:14 +08:00
同意楼上的,或者你可以通过归一化的思想,将[a,b]归一化为[ 0,x]区间,剩下的就是简单的红包问题了
kiracyan
2021-01-18 15:12:21 +08:00
@kaiki 纯随机肯定会出现你说的这种情况的
我的理解是从业务的角度去处理这个问题
Random(a,b) 就会出现 不够分或者分多的情况
Random(a,x) 超过最大值的当 b 就会出现 前面分的多 后面分的少的情况
sillydaddy
2021-01-18 15:15:14 +08:00
贴个现成的答案吧。楼上的方法都不对。

“生成满足约束的随机数的方法”
https://blog.csdn.net/maintony/article/details/88540320
Sapp
2021-01-18 15:19:09 +08:00
我觉得你可以试一下先平均
比如 40 块钱 10 个人,然后取一个范围随机,比如 2 (也就是你的 a ) 到 6 (你的 b ) 之间随机,这样最后总额加起来可能超了,比如 44 多了 4 块钱,那么就每个账户平均一下扣掉超出的金额( 0.4 ),如果最后加起来少了,比如 36 块钱,就每个账户平均一下加上剩余的 0.4 。
XiaoxiaoPu
2021-01-18 15:20:29 +08:00
@sillydaddy 第一个问题就错了,a1<x1<b1 这个条件被吃了
sillydaddy
2021-01-18 15:32:03 +08:00
@sillydaddy
@XiaoxiaoPu
好吧,那篇文章我也看不懂!!
但楼上的方法都是错的,这点我可以坚持。
chengfeng1992
2021-01-18 15:33:00 +08:00
@kaiki @sillydaddy #10 我在#7 说的确实不对,还是没解决最后一个值在区间内的问题,请忽略。
我再想一想。
chenluo0429
2021-01-18 15:57:58 +08:00
你可以先想象一下,先给 y 个数字位置都分配 a,那么问题就变成了把数字(x -ya)随机分成 y 个数字,且这些数字满足[0, b - a]。
现在问题就可以转化为,将一个数字 X 分成 y 个数字,这些数字满足[0, A],其中 X = x -ya, A = b - a 。
再提供一个取巧的方法,应该不是完全随机。
先生成 y 个[0, A]的数字,分别为 a1 到 ay,其和为 C 。然后对原 ai 进行转化,即 ai = ai * C / X 。这个时候 ai 数列的和就大致与 X 相等,将其和与 X 的差值再随机分配给任一个数字即可。如果无法分配则继续往第二第三个数字分。
FFFire
2021-01-18 16:12:45 +08:00
你首先要明确 a,b 和 x,y 的关系才行,这样就可以用#15 的方法了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/745915

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX