函数总是返回零

时间:2019-12-30 20:51:25

标签: c++ math probability

我正在尝试编写一个可以解决以下问题的函数:

假设您有一副由 n 张牌组成的牌,其中有些牌属于某些类别。从卡组的所有 s i 中抽出 c i 张牌的概率是多少?类别 i ,前提是允许您从卡组中抽出 k 张牌,并给予 r 返还您抽出的所有牌的机会与您的搜索不匹配,然后抽出与您返回的数字相等的数字卡?

n k r 作为单独的参数传递,而 s i c i 与数组的大小成对地作为数组传递。调用的主要函数是DrawChanceEx(),答案存储在参数answer中。

无论出于何种原因,下面的函数始终返回零。有人可以告诉我怎么了吗?

这是我的代码:

#include <iostream>
#include <vector>

using namespace std;

typedef struct {
    __int64 s;
    __int64 c;
} CardReq;


int main() {
    double answer;
    CardReq DrawReqs[] {{4, 2}, {2, 1}, {2, 2}};
    DrawChanceEx(answer, 28, 8, 3, 3, DrawReqs);
    cout << answer;
    return 0;
}

typedef struct {
    __int64 s;
    __int64 c;
    __int64 h = 0;
    __int64 i = 0;
    __int64 s_h;
    __int64 n_ss;
    __int64 n_ss_hh;
    __int64 min_hh = 0;
    __int64 min_cc;
    bool drawn = false;
} CardInfoEx;

typedef struct {
    __int64 hh;
    vector<CardInfoEx> cardlist;
} CardInfoListEx;

typedef struct {
    __int64 ss;
    __int64 cc;
    __int64 n_ss;
    ULONG_PTR count;
    ULONG_PTR mcount;
    vector<CardInfoListEx> cards;
} DrawInfoEx;


bool DrawChanceEx(double& answer, __int64 n, __int64 k, __int64 r, ULONG_PTR count, CardReq DrawReqs[]) {
    static CardInfoEx ph;
    ULONG_PTR isc = 0; __int64 ss = 0, cc = 0; CardInfoListEx cards; cards.cardlist.resize(count);
    for (struct {ULONG_PTR i; CardInfoEx& card;} loop {0, ph}; loop.i < count; ++loop.i) {
        if (DrawReqs[loop.i].s < 0 or DrawReqs[loop.i].c < 0)
            return false;
        if (DrawReqs[loop.i].s < DrawReqs[loop.i].c)
            ++isc;
        loop.card = cards.cardlist[loop.i];
        loop.card.s = DrawReqs[loop.i].s;
        loop.card.c = DrawReqs[loop.i].c;
        ss += loop.card.s; cc += loop.card.c;
        loop.card.s_h = loop.card.s;
        loop.card.n_ss_hh = loop.card.n_ss = n - ss;
    } if (n < ss)
        return false;
    if (k < cc or isc > 0) {
        answer = 0; return true;
    } for (ULONG_PTR i = 0; i < count; ++i)
        cards.cardlist[i].min_cc = cc -= cards.cardlist[i].c;
    DrawInfoEx DrawArray {ss, cc, n - ss, count, count - 1};
    DrawArray.cards.resize(r + 1); DrawArray.cards[r] = cards;
    answer = DrawChanceEx_Draw(n, k, r, DrawArray);
    return true;
}

double DrawChanceEx_Draw(const __int64& n, const __int64& k, const __int64& r, DrawInfoEx& DrawArray) {
    return (r == 0 ? double (DrawChanceEx_RecurseFinal(k, 0, 0, DrawArray)) : DrawChanceEx_Recurse(n, k, r, 0, 0, DrawArray))
        / DrawChance_nCr(n - DrawArray.cards[r].hh, k - DrawArray.cards[r].hh);
}

double DrawChanceEx_NextDraw(const __int64& n, const __int64& k, __int64 r, DrawInfoEx& DrawArray) {
    static CardInfoEx ph;
    CardInfoListEx& cards = DrawArray.cards[r - 1] = DrawArray.cards[r];
    cards.hh = 0;
    for (struct {ULONG_PTR i; CardInfoEx& card;} loop {0, ph}; loop.i < DrawArray.count; ++loop.i) {
        loop.card = cards.cardlist[loop.i];
        cards.hh += loop.card.h = min(loop.card.i, loop.card.c);
        loop.card.s_h = loop.card.s - loop.card.h; loop.card.i = 0;
    } if (r > 1)
        for (struct {ULONG_PTR i; __int64 hh; CardInfoEx& card;} loop {0, cards.hh, ph}; loop.i < DrawArray.count; ++loop.i) {
            loop.card = cards.cardlist[loop.i];
            loop.card.n_ss_hh = loop.card.n_ss - cards.hh;
            loop.card.min_hh = loop.hh -= loop.card.h;
        }
    else
        for (struct {ULONG_PTR i; CardInfoEx& card;} loop {0, ph}; loop.i < DrawArray.count; ++loop.i) {
            loop.card = cards.cardlist[loop.i]; loop.card.n_ss_hh = loop.card.n_ss - cards.hh;
        }
    return DrawChanceEx_Draw(n, k, r - 1, DrawArray);
}

__int64 DrawChanceEx_RecurseFinal(const __int64& k, const __int64& ii, const ULONG_PTR& Level, DrawInfoEx& DrawArray) {
    if (Level == DrawArray.count)
        return DrawChance_nCr(DrawArray.n_ss, k - ii);
    CardInfoEx& card = DrawArray.cards[0].cardlist[Level];
    __int64 sum = 0;
    for (__int64 i = max(card.c, k - ii - card.n_ss_hh), limit = min(card.s, k - ii - card.min_cc); i <= limit; ++i)
        sum += DrawChance_nCr(card.s_h, i - card.h) * DrawChanceEx_RecurseFinal(k, ii + i, Level + 1, DrawArray);
    return sum;
}

double DrawChanceEx_Recurse(const __int64& n, const __int64& k, const __int64& r, const __int64& ii, const ULONG_PTR& Level,
        DrawInfoEx& DrawArray) {
    CardInfoEx& card = DrawArray.cards[r].cardlist[Level];
    double sum = 0; __int64 i = max(card.h, k - ii - card.n_ss_hh), limit = min(card.s, k - ii - card.min_hh);
    if (Level == DrawArray.mcount) {
        for (; i < card.c; ++i)
            sum += DrawChance_nCr(card.s_h, i - card.h) * DrawChance_nCr(DrawArray.n_ss, k - ii - (card.i = i))
                * DrawChanceEx_NextDraw(n, k, r, DrawArray);
        __int64 a_sum = 0;
        for (; i <= limit; ++i)
            a_sum += DrawChance_nCr(card.s_h, i - card.h) * DrawChance_nCr(DrawArray.n_ss, k - ii - (card.i = i));
        sum += a_sum * (Level == 0 or DrawArray.cards[r].cardlist[Level - 1].drawn ? 1 : DrawChanceEx_NextDraw(n, k, r, DrawArray));
    } else {
        card.drawn = false;
        for (; i < card.c; ++i)
            sum += DrawChance_nCr(card.s_h, i - card.h) * DrawChanceEx_Recurse(n, k, r, ii + (card.i = i), Level + 1, DrawArray);
        card.drawn = Level == 0 or DrawArray.cards[r].cardlist[Level - 1].drawn;
        for (; i <= limit; ++i)
            sum += DrawChance_nCr(card.s_h, i - card.h) * DrawChanceEx_Recurse(n, k, r, ii + (card.i = i), Level + 1, DrawArray);
    } return sum;
}

__int64 DrawChance_nCr(const __int64& n, const __int64& k) {
    return int64_nCr(n, n >> 1 < k ? n - k : k);
}

inline __int64 int64_nCr(const __int64& n, const __int64& k) {
    static vector<__int64> nCkMemory;
    static __int64 maxMem = 0x200000;
    if (k < 2)
        return k ? n : 1;
    __int64 nCk, nCk_div, start, half_n = n >> 1, index_offset = (half_n - 1) * (n - half_n - 2) + n - 5, index = index_offset + k,
        n_index = index_offset + 1;
    if (index < maxMem)
        if (index >= nCkMemory.capacity()) {
            __int64 newCapacity = (half_n + 1) * (half_n + 2) + n - 3;
            nCk = n;
            if (newCapacity > maxMem) {
                for (__int64 i = 2, n_i = n - 1; i <= k; ++i, --n_i)
                    nCk = (nCk_div = nCk / i) * n_i + (nCk - nCk_div * i) * n_i / i;
                return nCk;
            } nCkMemory.resize(newCapacity, 0);
            start = 2;
        } else if (k <= nCkMemory[n_index])
            return nCkMemory[index];
        else if (nCkMemory[n_index] != 0) {
            start = nCkMemory[n_index];
            nCk = nCkMemory[index_offset + start];
        } else {start = 2; nCk = n;}
    else {start = 2; nCk = n;}
    for (__int64 i = start, n_i = n - start + 1; i <= k; ++i, --n_i)
        nCkMemory[index_offset + i] = nCk = (nCk_div = nCk / i) * n_i + (nCk - i * nCk_div) * n_i / i;
    nCkMemory[n_index] = k;
    return nCk;
 }

0 个答案:

没有答案