贪心算法:推公式 耍杂技的牛
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;
}