把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,,打印出s的所有可能出现的概率。
可以使用动态规划来解决这个问题,因为每个骰子的点数都依赖于之前骰子的结果。
#include <iostream>
#include <vector>
#include <iomanip>
class DiceProbabilityCalculator {
private:
int n; // 骰子的数量
public:
DiceProbabilityCalculator(int num_dice) : n(num_dice) {}
std::vector<double> calculateProbabilities() {
// 初始化动态规划数组
// dp[i][j] 表示投掷 i 个骰子,点数和为 j 的次数
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(6 * n + 1, 0));
// 基础情况:一个骰子
for (int i = 1; i <= 6; i++) {
dp[1][i] = 1;
}
// 动态规划过程
for (int i = 2; i <= n; i++) {
for (int j = i; j <= 6 * i; j++) {
for (int k = 1; k <= 6 && k <= j; k++) {
dp[i][j] += dp[i - 1][j - k];
}
}
}
// 计算概率
std::vector<double> probabilities;
int total_possibilities = std::pow(6, n);
for (int i = n; i <= 6 * n; i++) {
double probability = static_cast<double>(dp[n][i]) / total_possibilities;
probabilities.push_back(probability);
}
return probabilities;
}
void printProbabilities() {
std::vector<double> probabilities = calculateProbabilities();
std::cout << n << "个骰子的点数和及其概率:" << std::endl;
for (int i = 0; i < probabilities.size(); i++) {
std::cout << "点数和 " << (i + n) << ": "
<< std::fixed << std::setprecision(5) << probabilities[i] << std::endl;
}
}
};
int main() {
int n;
std::cout << "请输入骰子的数量: ";
std::cin >> n;
DiceProbabilityCalculator calculator(n);
calculator.printProbabilities();
return 0;
}
这个程序实现了一个 DiceProbabilityCalculator
类,用于计算 n 个骰子点数和的所有可能概率。以下是代码的主要特点和解释:
- 类的私有成员
n
存储骰子的数量。 calculateProbabilities
方法实现了动态规划算法:- 使用一个二维数组
dp
来存储中间结果。 dp[i][j]
表示投掷 i 个骰子,点数和为 j 的次数。- 从基础情况(一个骰子)开始,逐步计算到 n 个骰子的情况。
- 使用一个二维数组
- 动态规划的核心思想是:n 个骰子的点数和等于 n-1 个骰子的点数和加上第 n 个骰子的点数。
- 计算完次数后,将其转换为概率(次数除以总可能性 6^n)。
printProbabilities
方法用于格式化输出结果。- 主函数中提供了一个简单的用户界面,允许用户输入骰子数量并查看结果。
这个实现方法的时间复杂度是 O(n^2 * 6),其中 n 是骰子的数量。这比暴力枚举所有可能性(时间复杂度为 O(6^n))要高效得多。