Для 6-стороннего кубика у вас есть «вектор вероятности» [1/6, 1/6, 1/6, 1/6, 1/6, 1/6]
, затем для каждого дополнительного кубика вы сворачиваете вектор с «вектором вероятности» следующего кубика, чтобы получить более длинный и более"колоколообразный" вектор.
[1/6, 1/6, 1/6, 1/6, 1/6, 1/6] * [1/6, 1/6, 1/6, 1/6, 1/6, 1/6] =
[1/36, 2/36, 3/36, 4/36, 5/36, 6/36, 5/36, 4/36, 3/36, 2/36, 1/36]
Вы можете закодировать его так: (Обратите внимание, что я вычеркнул знаменатели из свертки).
static std::vector<int> conv(const std::vector<int>& f, const std::vector<int>& g) {
const int nf = f.size();
const int ng = g.size();
const int n = nf + ng - 1;
std::vector<int> out(n);
for(int i = 0; i < n; ++i) {
const int jmn = (i >= ng - 1) ? i - (ng - 1) : 0;
const int jmx = (i < nf - 1) ? i : nf - 1;
for(int j = jmn; j <= jmx; ++j) {
out[i] += (f[j] * g[i - j]);
}
}
return out;
}
static void rollDice(const std::vector<int>& dice) {
std::vector<int> firstDie(dice[0], 1);
std::vector<int> a = firstDie;
int denominator = dice[0];
for (int i = 1; i < dice.size(); ++i) {
a = conv(a, std::vector<int>(dice[i], 1));
denominator *= dice[i];
}
for (auto aa : a) {
std::cout << aa << '/' << denominator << '\n';
}
}
int main() {
rollDice({6, 6});
rollDice({1, 2, 3, 4, 5});
}
Вывод:
1/36
2/36
3/36
4/36
5/36
6/36
5/36
4/36
3/36
2/36
1/36
1/120
4/120
9/120
15/120
20/120
22/120
20/120
15/120
9/120
4/120
1/120