抢红包原理分析

抢红包问题分析

问题描述:
设计抢红包算法,使得分配钱的概率随机,互不影响。
红包金额为100,红包数为10个,最小金额1元,最大50元,不存在小数。

第一种设计方案

设未抢红包的人数为n,剩余金额为m,当有人抢红包时,随机从 [1,m - (n - 1)*1]中随机一个金额,作为用户抢到的红包金额。依次设置m与n的值,当n=0,红包会被抢空。
设计缺陷:这种随机钱的方式,不能做到金额互不影响,越先抢的用户越有概率抢到大红包,因为前面的用户的最大值大,随机范围也大。

第二张设计方案

事先将红包等概率划分成n份,当有人抢红包时,只需从队列中一份金额的红包即可。那么如何做到等概率划分成n份呢。
先定义一个权重最大值 WEIGHT_BASE=10000,从[1,WEIGHT_BASE]中随机一个值wieght1,依次循环,可以得到weight1,weight2…weight10,将所有的权重相加,会得到一个总权重allweight,那么 weight1/allweight * 100就是第一份红包的金额,以此类推,可以得到n份红包的金额。

示例代码

如下代码仅供参考


```local table_insert = table.insert
local math_random = math.random
local math_ceil = math.ceil
local math_floor = math.floor
local WEIGHT_BASE = 10000

--随机权重
function RandomWeight(num)
    local weightList = {}
    local allWeight = 0
    local weight
    for i = 1, num do
        weight = math_random(1, WEIGHT_BASE)
        table_insert(weightList, weight)
        allWeight = allWeight + weight
    end

    return allWeight,weightList
end


--将红包按照权重划分
function Divide(total, allWeight, weightList, minPacket, maxPacket)
    local packetList = {}
    local tmpTotal = 0
    for i = 1, #weightList do
        local packetValue = math_floor(total * (weightList[i] / allWeight))
        packetList[i] = packetValue
        if packetValue > maxPacket then
            packetList[i] = maxPacket
        elseif packetValue < minPacket then
            packetList[i] = minPacket
        end
        tmpTotal = tmpTotal + packetList[i]
    end
    local diff = tmpTotal - total
    -- print("before diff:", diff)
    if tmpTotal ~= total then
        for i = 1, #packetList do
            if diff == 0 then
                break
            end
            local value = packetList[i]
            if diff > 0 then
                if value - diff > minPacket then
                    packetList[i] = value - diff
                else
                    packetList[i] = minPacket
                end
                diff = diff - (value - packetList[i])
            else
                if value - diff > maxPacket then
                    packetList[i] = maxPacket
                else
                    packetList[i] = value - diff
                end
                diff = diff + (packetList[i] - value)
            end
        end
    end
    return packetList
end

--total 红包总额
--num 红包个数
-- minPacket 最小红包
-- maxPacket 最大红包
function RobRedPacket(total, num, minPacket, maxPacket)
    if total <= 0 or num <= 0 or minPacket <= 0 or maxPacket <= 0 then
        print("参数错误")
        assert(false)
        -- return
    end
    if num * minPacket > total then
        print("红包总额不符")
        assert(false)
    end
    if maxPacket < minPacket then
        print("最小包金额超过最大包金额")
        assert(false)
    end
    if maxPacket > total then
        print("最大包超出金额上限")
        assert(false)
    end
    local allWeight,weightList = RandomWeight(num)
    -- print("权重如下:")
    -- print(table.concat(weightList, "  "))
    local packetList = Divide(total, allWeight, weightList, minPacket, maxPacket)
    print(string.format("红包总量:%d,红包数量:%d,最小红包:%d,最大红包:%d", total, num, minPacket, maxPacket))
    print(table.concat(packetList," "))
    Check(packetList, total, num, minPacket, maxPacket)
end

function Print(list, err)
    print(table.concat(list," "))
    if err then
        print(err)
        assert(false)
    end
end

function Check(packetList, total, num, minPacket, maxPacket)
    if num ~= #packetList then
        Print(packetList, "红包数量不对")
    end
    local tmpTotal = 0
    for i = 1, num do
        local value = packetList[i]
        tmpTotal = tmpTotal + value
        if value > maxPacket or value < minPacket then
            Print(packetList, "红包大小不符")
        end
    end
    if tmpTotal ~= total then
        Print(packetList, "红包总额不符:"..tmpTotal.."  ".. total)
    end
end

function Main()
    RobRedPacket(200, 10, 5, 100)
end

function Unittest()
    for i = 1, 10000 do
       local num = math_random(1,20)
       local total = math.random(num, num * 100)
       local minPacket = 1
       local maxPacket = total - (num - 1) * minPacket 
        RobRedPacket(total, num, minPacket, maxPacket)
    end
    print("success")
end

-- Main()
Unittest()

你可能感兴趣的:(lua,抢红包)