Python中如何实现微信发红包的算法?

比如 100 元红包 10 个人抢,以下算法:先随机生成 10 个数,之和等于红包金额,然后依次从这个列表随机取一个
,取了后移除,在随机取一个,这样算法是否合理,公平不呢

def hongbao(amount=5, count=3):
s = []
sum = 0
min = 0.01
max = float(amount) - count * 0.01
num = 0
for i in range(count-1):
num = round(random.uniform(0, float(amount) - sum), 2)
while num < min or num > max:
num = round(random.uniform(0, float(amount) - sum), 2)
sum += num
s.append(num)
s.append(round(float(amount) - sum, 2))
# return s
for i in range(count):
temp = random.choice(s)
print(“第{0}个人抢的红包是{1}”.format(i + 1, temp))
s.remove(temp)


hongbao(100, 10)

测试有问题,问题在哪里呢
Python中如何实现微信发红包的算法?


6 回复

难读…


import random

def wechat_red_packet(total_amount, num_people):
    """
    微信红包算法实现
    :param total_amount: 红包总金额(单位:元)
    :param num_people: 抢红包人数
    :return: 每个人分到的金额列表(单位:元)
    """
    if total_amount <= 0 or num_people <= 0:
        raise ValueError("金额和人数必须大于0")
    
    # 转换为分计算,避免浮点数精度问题
    total_cents = int(total_amount * 100)
    
    if total_cents < num_people:
        raise ValueError("每人至少能分到0.01元")
    
    # 生成n-1个分割点
    points = sorted(random.sample(range(1, total_cents), num_people - 1))
    
    # 计算每个区间的长度(即每个人分到的金额)
    result = []
    prev = 0
    for point in points:
        result.append((point - prev) / 100.0)  # 转换回元
        prev = point
    result.append((total_cents - prev) / 100.0)
    
    # 随机打乱顺序(微信红包金额是随机的)
    random.shuffle(result)
    
    return result

# 示例使用
if __name__ == "__main__":
    # 发一个100元的红包给10个人
    amounts = wechat_red_packet(100, 10)
    print(f"红包分配结果:{amounts}")
    print(f"总金额验证:{sum(amounts):.2f}元")

这个算法的核心是线段分割法:把总金额想象成一条线段,随机插入n-1个分割点,就能得到n个随机金额的线段。关键点有四个:1)用分而不是元计算避免浮点误差;2)保证每人至少0.01元;3)分割点不重复;4)最后打乱顺序让金额分布更随机。

实际微信的算法会更复杂些,加入了延迟计算和防作弊机制,但这个基础版本已经能满足大部分场景。

二倍均值法

我看了下那些 stackoverflow 的回复,
最简单的是生成 10 个随机数,然后按照比例来分 100 元

整理思路如下:

#算法一
#################################################################
def hongbao(amount=5, count=3):
s = []
min = 1 #分
amount = amount * 100 #单位分
max = amount - (count-1) #单位分
for i in range(count-1):
# num = random.randint(0, amount)
num = random.uniform(0, int(amount))
while num < min or num > max:
num = random.uniform(0, int(amount))
amount -= num
s.append(round((num / 100), 2))
s.append(round((amount / 100), 2))
random.shuffle(s)
return s
print(hongbao(1, 6))
##############################################################

算法二
#############################################################
# 0–|----|--------|-----------|-------20
# 0 2 4 10 16 20

def hongbao(amount=10, count=5):
ret = random.sample(range(1, amount * 100), count - 1) #分为单位
ret.extend([0, amount * 100]) #追加多个值 0 amount * 100
ret.sort() #排序
# return [((ret[i+1] - ret[i]) / 100 for i in range(num))] # 列表生产式
for i in range(count):
yield (ret[i+1] - ret[i]) / 100

res = hongbao(10, 6)
for i in res:
print(i)

回到顶部