贪心中的交换证明——AcWing 125. 耍杂技的牛
题意:有n头奶牛,重量为Wi,强壮度为Si。现以某种顺序叠罗汉,定义一头奶牛的风险值为:它上面的奶牛的总重量减去自身的强壮度。确定奶牛的排序使最大风险值最小。
假设我们还不知道按Wi+Si排序就是最优解
考虑相邻的两头奶牛i,i+1在交换前后风险值的情况
i | i+1 | |
---|---|---|
交换前 | W1+...+Wi-1 - Si | W1+...+Wi - Si+1 |
交换后 | W1+...+Wi-1+Wi+1 - Si | W1+...+Wi-1 - Si+1 |
我们将所有数据加上Si + Si+1 - (W1+...+Wi-1),不影响它们的大小关系,得到
i | i+1 | |
---|---|---|
交换前 | Si+1 | Wi + Si |
交换后 | Wi+1 + Si+1 | Si |
现在考虑原来的Wi,Si,Wi+1,Si+1满足什么关系,使得交换后的最大值一定变小(为方便表述,包含不变的情况)
也即求max(Si+1, Wi+Si) >= max(Wi+1 + Si+1, Si)的等价条件
分两种情况讨论
1.假设Wi + Si >= Si+1,则只需Wi+Si >= max(Wi+1 + Si+1, Si),只需满足Wi + S1 >= Wi+1 + Si+1
2.假设Wi + Si <= Si+1,则只需Si+1 >= max(Wi+1 + Si+1, Si),这是不可能的,因为Si+1 < Wi+1 + Si+1 <= max(Wi+1 + Si+1, Si)。
综上,当且仅当原来的两头相邻奶牛满足Wi + S1 >= Wi+1 + Si+1 时,交换两头牛的顺序一定会使这两头奶牛中的最大值变小。
放眼整个序列,所有相邻且Wi + S1 >= Wi+1 + Si+1的奶牛都可以通过交换保证得到更优的答案,因此当奶牛按Wi + Si从小到大排序时一定可以得到最优解。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
struct Cow {
int w, s;
} c[maxn];
int sum[maxn];
bool cmp(Cow a, Cow b) { return a.w + a.s < b.w + b.s; }
int main() {
int n; cin >> n;
for (int i = 0; i < n; i++) cin >> c[i].w >> c[i].s;
sort(c, c + n, cmp);
int ans = -inf;
for (int i = 0; i < n; i++) {
sum[i] = i ? sum[i-1] + c[i].w : c[i].w;
ans = max(ans, sum[i-1] - c[i].s);
}
cout << ans;
return 0;
}