1. 问题背景与理解
2005年11月USACO黄金组这道"奶牛玩杂技"题目,乍看之下像是个有趣的农场故事,实则考察了经典的贪心算法应用。题目描述了一群奶牛想要叠罗汉表演杂技,每头牛有自己的重量(W)和力量(S),我们需要找到一个叠放顺序,使得所有牛中"被压扁程度"的最大值最小化。
所谓"压扁指数",数学表达就是:对于处在某个位置的牛i,其压扁指数=它上方所有牛的重量总和-它自身的力量。我们的目标是最小化整个叠罗汉结构中最大的那个压扁指数。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路分析
2.1 问题转化与关键观察
这个问题本质上是一个排序问题——我们需要确定奶牛的叠放顺序。关键在于发现正确的排序标准。直觉可能告诉我们:
- 把力量大的牛放在下面(因为它们能承受更多重量)
- 把重量轻的牛放在上面(减少下方牛的压力)
但单独使用任一种策略都不能得到最优解。通过深入分析,我们发现应该按照(W+S)的值来排序:
- 对于相邻的两头牛i和j,无论谁在上方,另一方承受的风险值是固定的
- 比较两种排列方式的风险值,可以推导出(Wi+Si)和(Wj+Sj)的关系决定了最优顺序
2.2 贪心策略证明
假设有两头牛A和B:
- 如果A在B上方:B的风险=Wa - Sb
- 如果B在A上方:A的风险=Wb - Sa
我们需要选择使max(Wa-Sb, Wb-Sa)较小的排列方式。通过不等式推导可以发现,当Wa+Sa < Wb+Sb时,应该把A放在B上方。
这个局部最优选择可以推广到全局,因此按照(W+S)升序排列是最优策略。
3. 算法实现详解
3.1 数据结构设计
我们使用一个结构体来存储每头牛的信息:
cpp复制struct Node {
int w; // 重量
int s; // 力量
bool operator < (Node &t) {
return w + s < t.w + t.s;
}
} a[MAX_N];
重载小于运算符是为了方便直接使用STL的sort函数进行排序。
3.2 算法流程
- 输入所有牛的重量和力量
- 按照(w+s)升序排序
- 计算最大风险值:
- 维护一个累计重量t,表示当前牛上方所有牛的重量总和
