贪心算法:推公式 耍杂技的牛
C++
AcWing 125. 耍杂技的牛
/* 题目描述: Acwing 125. 耍杂技的牛: 农民约翰的 N 头奶牛(编号为 1..N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。 奶牛们不是非常有创意,只提出了一个杂技表演: 叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。 奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。 这 N 头奶牛中的每一头都有着自己的重量 Wi 以及自己的强壮程度 Si。 一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。 您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。 输入格式: 第一行输入整数 N,表示奶牛数量。 接下来 N 行,每行输入两个整数,表示牛的重量和强壮程度,第 i 行表示第 i 头牛的重量 Wi 以及它的强壮程度 Si。 输出格式: 输出一个整数,表示最大风险值的最小可能值。 数据范围: 1 ≤ N ≤ 50000, 1 ≤ Wi ≤ 10,000, 1 ≤ Si ≤ 1,000,000,000 解题思路: 对于本题,乍一看基本没什么明显的思路,因此,我们从交换 i 和 i + 1 牛的位置入手,查看什么时候交换 i 和 i + 1 牛的位置,可以使得其对结果更好。 为什么选择 i 和 i + 1 ? 因为 交换 i 和 i + 1头牛的位置,对其他位置的牛危险值的计算没有影响,他**只会影响** i 和 i + 1 头牛风险值的大小。 那么,我们只需要通过查看交换时候风险值是否变大,来决定是否需要交换。 公式推导部分: 首先我们假设当前顺序奶牛们的重量为 w1, ..., wn, 强壮程度 s1, ..., sn,方便比较假设 x = sum(w1, ..., w(i-1)) 可得 **交换前风险值** 第 i 头奶牛: x - si 第 i + 1 头奶牛: x + wi - s(i+1) 可得 **交换后风险值** 第 i 头奶牛: x - s(i+1) 第 i + 1 头奶牛: x + w(i+1) - s(i) 需要交换的情况: max(x - si, x + wi - s(i+1)) > max(x - s(i+1), x + w(i+1) - s(i)) 不需要交换的情况 max(x - si, x + wi - s(i+1)) < max(x - s(i+1), x + w(i+1) - s(i)) 也就是我们需要选择 i 和 i + 1 头奶牛 max 风险值最小的那一个。我们以不需要交换情况为基础进行推导 该问题可以选择的推导思路,首先判断 x - si 和 x + wi - s(i+1)的大小 1. (x - si) < (x + wi - s(i+1)) 即为 s(i+1) - s(i) < w(i) max(x - si, x + wi - s(i+1)) = x + wi - s(i+1) < max(x - s(i+1), x + w(i+1) - s(i)) 因为 x + wi - s(i+1) >= x - s(i+1) 显然成立, 因此不等式成立条件为 x + wi - s(i+1) < x + w(i+1) - s(i) 即为: wi + si < w(i+1) + s(i+1) 2. (x - si) > (x + wi - s(i+1)) 即为 s(i+1) - s(i) > w(i) max(x - si, x + wi - s(i+1)) = x - si < max(x - s(i+1), x + w(i+1) - s(i)) 因为 x - si <= x + w(i+1) - s(i)) 显然成立, 因此等式恒成立。 讨论一可以得之,不等式成立条件为 s(i+1) - s(i) < w(i) && wi + si < w(i+1) + s(i+1) 讨论二可以得之,不等式成立条件为 s(i+1) - s(i) > w(i) && True,然而 s(i+1) - s(i) > w(i) 包含了 wi + si < w(i+1) + s(i+1) 因此,不等式成立条件为 wi + si < w(i+1) + s(i+1)。 即为 wi + si < w(i+1) + s(i+1) 不需要交换 i, i + 1 wi + si > w(i+1) + s(i+1) 需要交换 i, i + 1 wi + si < w(i+1) + s(i+1) 可以交换 i, i + 1,也可以不交换。 目前为止,我们只是推导出了 i 和 i + 1 的交换特性,该特性是否具有传递性呢? **答案是具有的,因为 wi + si < w(i+1) + s(i+1) 本身只是和自身属性相关,具有传递性。** 综上证明完毕,排序条件为 wi + si < w(i+1) + s(i+1) */ #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; typedef pair<int, int> PII; typedef long long LL; const int N = 50010; PII a[N]; int n; bool cmp(const PII &t1, const PII &t2) { return t1.first + t1.second <= t2.first + t2.second; } LL solution() { LL res = -1e15; LL pre_weight_sum = 0; sort(a + 1, a + n + 1, cmp); for (int i = 1; i <= n; i ++ ) { res = max(res, pre_weight_sum - a[i].second); pre_weight_sum += a[i].first; } return res; } int main() { // input scanf("%d", &n); for (int i = 1; i <= n; i ++ ) { scanf("%d%d", &a[i].first, &a[i].second); } LL res = solution(); printf("%d\n", res); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战