如何把一个数字 x 随机分成 y 个数字,这些数字≥a 且≤b
把 a ~ b 的范围,转换成上面算法要求的 0 ~ d 即可。
然后给每个值分最小值之后的余数 remainder = x – a*y
再然后把余数随机分成 y 份,其中最大值 max = b – a,最小值 min = 0,相当于把问题转化成了简单的红包算法
最后把分成的值分别+a 得到结果
坐等高手。
对于第二个数,转化为数字 x – r1 分成 y – 1 个数字,这些数字≥a 且≤b,同上可得 r2
“生成满足约束的随机数的方法”
https://blog.csdn.net/maintony/article/details/88540320
就是每次分配完,判断剩余金额是否在合理范围内,在就继续,不在就重新分配。
“`
from random import randint
def hongbao(x, y, a, b):
result = []
for i in range(y):
result.append(randint(a, b))
while x – sum(result) > b * (y – i – 1) or x – sum(result) < a * (y – i – 1):
result[i] = randint(a, b)
return result
r = hongbao(100, 10, 5, 15)
print(r, sum(r))
“`
优化的时候加一个最后一次直接求结果就行。
我可以举个肉眼可见的例子,
x=11,y=3,a=1,b=5,意思就是 11 元红包分给 3 个人,最小 1 元,最大 5 元。
简单看一下 3 个人分得的红包分布
1,5,5
2,4.5,4.5
3,4,4
4,3.5,3.5
5,3,3
可以看出来,后面抽红包的两个人,他们的平均期望值是 4,而第一个人的期望只有 3 。
这说明这种算法不是均匀随机的。
1. 数字 x 平均分成 y 份
2. random 1 个差值,从 y 份中取出 2 个数,第 1 个加上这个差值,第 2 个减去这个差值,得到的 2 个结果如果满足 >=a 且 <=b,就相当于随机分配了 2 个数字。一直循环到分配完成。
3. 可以 random 多个差值,附加到 y 份中多份数字上
选择一个数字 k (见脚注如何选择 k )。如果它大于 R,那么将它设为 R (k=min(k,R) )。随机选取一个红包 i 。如果 Ci 小于 k,则 k 设为 Ci ( k=min(k,Ci) )。现在将 k 部分钱放入红包 i 中,更新 R 和 Ci ( R=R-k,Ci=Ci-k )。重复这个过程,直到所有的红包都被分完( R=0 )。
脚注:挑选 k 个
你可以设置 k=1 或从任何适当的分布中选择 k (例如:从 1 到 10 中随机选择 k )。
import random
def distPotato(R, N, minP, maxP):
C = [maxP-minP for i in range(N)]
V = [minP for i in range(N)]
R-=sum(V)
while(R>0):
k = random.uniform(0, 10)
i = random.choice(range(N))
k = min(k,R)
k = min(k, C[i])
C[i]-=k
R-=k
V[i]+=k
return V
v = distPotato(100.5,3,15.2,60.3)
可参考原答案(离散和连续应该是一样的道理): https://stackoverflow.com/questions/10561804/randomly-put-elements-into-n-buckets/10561932
`weight * weight` 也许可以改为 `Math.sqrt(weight)` 或其他运算,获得更好的平权效果,没细想
换个实际的例子理解一下,把你的参数微调一下:a=5, b=11,那么如果完全随机的话,是不是按理说 5 的概率较低,10 或 11 的概率要高得多?但是你的算法在第一步给出 X1 随机变量是 [5, 11] 内均匀分布的。
不断重复以上步骤,直到最穷的人财富大于等于 a,最富的人财富小于等于 b 。
@cassyfar,#37,最小值最大值只是一个约束吧,并不一定要求一定要取到最小或最大值。
想了一下,找到了一个我认为正确的方法。
但基本原理很简单,就是类似前面提到的,在多边形内随机采样取点。
先看一下为什么发红包跟多边形取点会关联起来,举例来说,发红包的条件可以表示为:
x+y+z=11,(给 3 个人发 11 元红包)
x>=2, x<=8, y>=2, y<=8, z>=2, z<=8,
(给每个人发的红包在 2 和 8 之间)
用几何的观点来看,这几个条件表示的是,使用一个立方体(x,y, z 的范围都在 2 ~ 8 之间),去截取一个平面,平面的方程为 x+y+z=11 。平面被立方体截取的部分(在立方体内的),就是满足题目要求的解。然后求一个随机解就变成了在被截取的平面上随机采样采点。
如果把这个图形画出来,会发现平面被立方体所截得的图形是一个等边三角形。三个顶点分别是(2,2,7),(2,7,2),(7,2,2)
所以,现在的问题变成了:已知一个三角形(凸多边形),怎么才能做到均匀采样其内部的点?
这个就要感谢凸集的美好性质了:凸集内部的任何一点都可以唯一表示成凸集顶点的线性组合。
假设三角形的三个顶点分别是 P0, P1, P2,那么三角形内部的任一点,可以唯一表示为 a*P0+b*P1+c*P2,其中 a+b+c=1 。
所以要想随机采样三角形内部的点,只要随机取 a,b,c 这三个数,保证和为 1 即可。
上面是 3 维的简单情形,如果发红包给更多的人,就变成了更高维的,但原理是一样的。原来的平面变成了高维平面,原来的立方体变成了高维立方体。关键是求出立方体在平面上截得的顶点。找到所有的顶点后,对这些顶点线性组合就 ok 了。