题解:洛谷 P2911 Bovine Bones
【题目来源】
洛谷:P2911 [USACO08OCT] Bovine Bones G - 洛谷
【题目描述】
Bessie 喜欢桌游和角色扮演游戏,所以她说服了 Farmer John 驾车送她去爱好商店,在那里她购买了三个用于掷骰子的骰子。这些公平的骰子分别有 \(S_1\)、\(S_2\) 和 \(S_3\) 个面(\(2 \leq S_1 \leq 20\);\(2 \leq S_2 \leq 20\);\(2 \leq S_3 \leq 40\)),上面分别包含 \(1\) 到 \(S_1\),\(S_2\) 和 \(S_3\) 之间的所有整数。Bessie 不断地掷骰子,试图找出哪个三个骰子的点数和出现得最频繁。如果有多个和出现得最频繁,输出其中最小的和。
【输入】
第 1 行:三个用空格分隔的整数:\(S_1\)、\(S_2\) 和 \(S_3\)。
【输出】
第 1 行:当骰子以每种可能的组合掷出时,出现次数最多的最小整数和。
【输入样例】
3 2 3
【输出样例】
5
【核心思想】
-
问题分析:给定三个骰子的面数 \(S_1, S_2, S_3\),每个骰子掷出 \(1\) 到 \(S_i\) 的整数,求三个骰子点数和出现次数最多的最小值。由于 \(S_i \leq 40\),总组合数最多 \(20 \times 20 \times 40 = 16000\),直接枚举所有组合统计即可。本质上是暴力枚举 + 计数问题。
-
算法选择:
- 三重循环枚举:遍历所有 \((i, j, k)\) 组合,\(i \in [1, S_1]\),\(j \in [1, S_2]\),\(k \in [1, S_3]\)
- 频数统计:用数组 \(a[sum]\) 记录点数和 \(sum = i + j + k\) 的出现次数
-
关键步骤:
- 读取数据:读入 \(S_1, S_2, S_3\)
- 枚举所有组合:
- \(i = 1\) 到 \(S_1\),\(j = 1\) 到 \(S_2\),\(k = 1\) 到 \(S_3\)
- \(a[i + j + k] \leftarrow a[i + j + k] + 1\)
- 找最大频数的最小和:
- 初始化 \(max = a[3]\),\(ans = 3\)(最小可能和为 \(3\))
- 遍历 \(i = 3\) 到 \(S_1 + S_2 + S_3\):
- 若 \(a[i] > max\),更新 \(max = a[i]\),\(ans = i\)
- 输出 \(ans\)
-
时间/空间复杂度:
- 时间复杂度:\(O(S_1 \cdot S_2 \cdot S_3)\),最多 \(16000\) 次枚举
- 空间复杂度:\(O(S_1 + S_2 + S_3)\),频数数组大小
-
暴力枚举的核心思想:
- 数据范围决定算法:\(S_3 \leq 40\) 使得总组合数极小,无需任何优化技巧,直接枚举即可
- 频数数组的索引设计:和的范围为 \([3, S_1+S_2+S_3]\),直接以和值为下标,\(O(1)\) 统计
- 最小和的处理:遍历从小到大,遇到更大频数才更新,保证相同频数时取最小和
- 骰子公平性:每个面等概率,枚举即等权重统计,无需额外概率计算
- 适用于小范围枚举、频数统计、概率分布类问题
【解题思路】

【算法标签】
入门 #模拟
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
int main()
{
int s1, s2, s3; // 定义变量:三个骰子的面数
int a[85] = {0}; // 定义数组:统计各点数出现的次数(初始化为0)
cin >> s1 >> s2 >> s3; // 输入三个骰子的面数
// 三重循环遍历所有可能的骰子组合
for (int i = 1; i <= s1; i++)
{
for (int j = 1; j <= s2; j++)
{
for (int k = 1; k <= s3; k++)
{
a[i + j + k]++; // 统计当前点数出现的次数
}
}
}
// 初始化最大值和结果(最小可能的点数是3)
int max = a[3]; // 当前最大出现次数
int ans = 3; // 对应的点数
// 遍历所有可能的点数(从3到s1+s2+s3)
for (int i = 3; i <= s1 + s2 + s3; i++)
{
// 如果当前点数出现次数更多,则更新最大值和结果
if (a[i] > max)
{
max = a[i]; // 更新最大出现次数
ans = i; // 更新结果点数
}
}
cout << ans; // 输出出现次数最多的点数
return 0; // 程序正常结束
}
【运行结果】
3 2 3
5
浙公网安备 33010602011771号