我正在尝试编写一个可以解决以下问题的函数:
假设您有一副由 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;
}