网上流传的红包 Money 分配算法

代码不长,直接看 getMoneyRandomly 就好:

# -*- coding: UTF-8 -*-
__author__ = 'haoyu'

import math
import random


class RedPack:
    peopleTotal = 0
    peopleLeft = 0.0
    moneyTotal = 0
    moneyLeft = 0.0

    isInitlized = False
    isFinish = True

    def __init__(self, people, money):
        # 金额取两位小数
        money = round(money, 2)

        if money <= 0.01:
            print('错误:金额不能少于 0.01 元')
            return
        if people < 1:
            print('错误:至少 1 人')
            return
        if (math.floor(money * 100 / people)) / 100 < 0.01:
            print('错误:每人至少 0.01 元')
            return

        # 初始化
        self.peopleTotal = people
        self.peopleLeft = people
        self.moneyTotal = money
        self.moneyLeft = money
        self.isInitlized = True
        self.isFinish = False

        print('总金额: %.2f 元,总人数: %2d 人' % (self.moneyLeft, self.peopleTotal))
        print()

    def getMoneyRandomly(self):
        money = 0
        # 验证
        if not self.isInitlized:
            print('错误:没有初始化')
            return money
        if self.isFinish:
            print('错误:已经分配完毕')
            return money

        # 分配 Money
        if self.peopleLeft == 1:
            self.isFinish = True
            money = self.moneyLeft
        else:
            minMoney = 0.01
            maxMoney = self.moneyLeft / self.peopleLeft * 2
            money = random.random() * maxMoney
            money = max(money, minMoney)
            money = min(money, self.moneyLeft - (self.peopleLeft - 1) * minMoney)

        # 分配过后的一些收尾工作
        self.peopleLeft -= 1
        money = round(money, 2)
        self.moneyLeft -= money

        return money


moneyPack = RedPack(10, 10)  # 10 个人,总共分 10 元钱
totalMoney = 0
for i in range(moneyPack.peopleTotal):
    money = moneyPack.getMoneyRandomly()
    print('第%d 人: %.2f 元,剩余 %.2f 元' % (i + 1, money, moneyPack.moneyLeft))
    totalMoney += money

print()
print('分配: %.2f 元,剩余: %.2f 元' % (totalMoney, moneyPack.moneyLeft))

原来的版本内部都是 float 实现的,但是好像处理小数精度会出一点问题,导致总是有几分钱分配不完。

然后内部就改成了 int 来玩了(两位定点小数嘛,还算好处理),稍微好了一点吧。

然后,觉得这样有些不妥,里面要脑补一个 100 的转换。于是还改为 float,但是使用 round()函数。这下更好一点了。

不理解,为什么要 “最多能得到平均值的 2 倍”,这个设定有什么意义?

还有,按照这个代码,10 个人瓜分 0.2 元钱,第一个人最多拿到 0.04 元,但是在 WX 某次红包中,我发现第一个人拿到了 0.05 元。很是奇怪錒~

总之呢,一段比较有趣的代码。

玩开心就好~

留下评论