遊戲裏面的容斥原理

咱們處理遊戲Boss掉落時常常碰到一個問題,假設這個BOSS會掉3個部位的裝備,程序員

武器:20% 衣服:30% 頭盔:50%算法

那麼求,指望次數多少,能夠集齊這三件裝備數組

做爲程序員,咱們先來一段暴力破解,循環1000000萬次,也便於咱們驗證解果dom

math.randomseed(tostring(os.time()):reverse():sub(1, 6))

local counts = {}

local p1, p2, p3 = 0.2, 0.3, 0.5

for j=1, 10000 do
    local a1, a2, a3 = 0, 0, 0

    for i=1,1000000 do
        local r = math.random()
        if r > p3 then
            a3 = a3 + 1
        elseif r > p2 then
            a2 = a2 + 1
        else
        --elseif r > p1 then
            a1 = a1 + 1
        end

        if a1 > 0 and a2 > 0 and a3 > 0 then
            table.insert(counts, i)
            break
        end
    end
end

print(avg_count/#counts) --打印結果,固然你不必定是這個值:6.6702

可是這出來也只是個近似值,獲得一個靠譜值,這個時候容斥原理就出來了,如下解釋得真好:spa

若是被計數的事物有A、B、C三類,那麼,A類和B類和C類元素個數總和= A類元素個數+ B類元素個數+C類元素個數—既是A類又是B類的元素個數—既是A類又是C類的元素個數—既是B類又是C類的元素個數+既是A類又是B類並且是C類的元素個數。(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)code

再放一下圖:blog

因此:算法變成這樣:遊戲

print(1/p1+1/p2+1/p3 - 1/(p1+p2) - 1/(p2+p3) - 1/(p1+p3) + 1/(p1+p2+p3))

那若是部位多,那也真夠累的,寫個通用算法:ip

--傳入數組,取裏面的幾個元素進行組合
local function combine(arr, n, m, b, result)
    n = n or #arr
--print(' combine', n, m, arr[n])
    assert(n >= m)
    for i=m, n, 1 do
        b[m] = i
        if m > 1 then
            combine(arr, i - 1, m - 1, b, result)
        else
            --用於打印
            local s = {}
            table.foreach(b,function(_,v)
                table.insert(s,arr[v])
            end)
            table.insert(result, s)
        end
    end
end

--combine({'a','b','c', 'd'},nil,2,{})

--將數組相加
local function add(arr)
    assert(type(arr)=='table')
    local r = 0
    for i,v in pairs(arr) do
        r = r + v
    end
    return r
end

--容斥原理
function InclusionExclusion (ppp)
    local result = 0
    for i,v in ipairs(ppp) do
        result = result + 1/v
    end


    local count = #ppp
    for i=2,count - 1 do
        local c = {}
        combine(ppp, nil, i, {}, c)
        --遍歷全部的組合
        table.foreach(c, function(_,v)
            --計算組合裏面全部的數
            result = result - 1/add(v)
        end)
    end

    result = result + 1/add(ppp)

    return result
end

print(InclusionExclusion({p1,p2,p3}) --打印值:6.6547619047619
相關文章
相關標籤/搜索