公平法
红包剩余金额为 M
红包剩余数量为 N
这种算法就是每次都在区间[0,M/N×2] 随机取一个数。假设100元红包发10个人,那么合理的做法应该是每个人领到10元的概率相同。
- 第一个人随机金额的范围为[0,100/10×2] ,也就是[0,20],这样平均可以领到10元,此时剩余金额为100-10=90。
- 第二个人随机金额的范围为[0,90/9×2] ,也就是[0,20],这样平均也可以领到10元,此时剩余金额为90-10=80。
- 第三个人随机金额的范围为[0,80/8×2] ,也就是[0,20],这样平均也可以领到10元。
- 第N个人拿到剩余的金额,不需要随机数。
这样推导下去,每个人领到相同金额的概率应该就是相同的了。
- 注意:这种方法有溢出风险,可能最后分配的变成负数也不是不可以。
我的解决思路:
第一次生成随机数:k1=(0,sum/n*2)
(左开右开区间内的随机数)
第二次生成随机数:k2 = (0,(sum-k1)/(n-1)*2)
第三次生成随机数:k3 = (0,(sum-k1-k2)/(n-2)*2)
第N次生成随机数:kn = sum-k1-...-kn-1
import random
import numpy as np
def getredpocket(sums,n):
minnum=0.000000001
# 避免出现0的极端小概率情况
return random.uniform(minnum,(sums/n)*2-minnum)
def run(sums,n):
s=[]
for i in range(n,1,-1):
red=getredpocket(sums,i)
sums-=red
s.append(red)
s.append(sums)
for i in s:
if i<=0:
print("fuck!!!!")
# 只要有负数或者0就会在sum函数报错从而发现程序问题
return "fuck!!!!"
return s
terms=10000
sums=1000000
n=10000
for i in range(terms):
r=run(sums,n)
print("No."+str(i+1)+" terms:")
print("u:",sum(r)/n,end=" ")
print("σ:",np.var(r))
print()
线段切割法
这个算法可以把总金额想象成一条线段,每个人都有机会切一刀,前面的人切剩下的后面的人再接着切,这样越是前面的人截取的长度(理解成领取到的红包金额)越大的概率就越大。