扔n个骰子,第i个骰子有可能投掷出Xi种等概率的不同的结果,数字从1到Xi。所有骰子的结果的最大值将作为最终结果。求最终结果的期望。
输入描述:
第一行一个整数n,表示有n个骰子。(1 <= n <= 50) 第二行n个整数,表示每个骰子的结果数Xi。(2 <= Xi <= 50)
输出描述:
输出最终结果的期望,保留两位小数。
示例1
输入
2 2 2
输出
1.75
分析:这道题本身是蛮简单的,但比较难理解的是题意,主要考察概率论的知识。为了方便分析,我以三个骰子为例:例如Xi所给定的输入依次为:X1 = 3, X2 = 2,X3 = 3
那么我们可以取到的结果如下:
1 : 假设这三个骰子当中取到的最大值为1,则第一个骰子只能选择一种,第二个骰子只能选择一种,第三个骰子只能选择一种,即共有 1 * 1 * 1 = 1 种情况
2: 同理,假设这三个骰子当中取到的最大值为2, 则第一个骰子可以选择2种(1或者2),第二个骰子可以选择2种,第三个骰子可以选择2种,我们要排除 1 1 1 这种情况,因为当前取到的最大值为2,即至少有一个骰子取值为2,共有 2*2*2 - 1*1*1 = 7种可能
3:同理,假设这三个骰子当中取到的最大值为3,则第一个骰子可以选择3种(1或者2或者3),第二个骰子可以选择2种(最大值只能到2),第二个骰子可以选择3种,排除最大值为2的情况,即共有 3*2*3 - 2*2*2 = 10 种情况。
所有骰子出现的情况共有:3*2*3=18种。
取到1的可能性为: 1 / 18; 取到2的可能性为: 7 / 18;取到3的可能性为: 10 / 18;
根据高中概率论的知识即可求解出期望:1 * 1 / 18 + 2 * 7 / 18 + 3 * 10 / 18
特别注意的一点是:数据类型取double,int部分结果会溢出,而且很难找出原因。具体代码如下:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
class solution {
public:
double getMaxException(vector<int>& values, const int maxValue) {
double allPossibleNum = 1;
for (int& value: values) allPossibleNum *= value;
double res = 0.0;
for (int curValue = 1; curValue <= maxValue; ++curValue) {
double cnt = 0, cur_mul = 1, pre_mul = 1;
for (auto& value: values) {
cur_mul *= min(value, curValue);
pre_mul *= min(value, curValue - 1);
}
cnt = cur_mul - pre_mul; //获取取到Xi对应的所有可能结果
res += curValue * cnt / allPossibleNum;
}
return res;
}
};
int main() {
int N;
cin >> N;
vector<int> values(N, 0);
int maxValue = 0;
for (int pos = 0; pos < N; ++pos) {
cin >> values[pos];
maxValue = max(maxValue, values[pos]);
}
printf("%.2f\n", solution().getMaxException(values, maxValue));
return 0;
}