贪心中的交换证明——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;
}
posted @ 2021-09-02 12:42  _vv123  阅读(48)  评论(0编辑  收藏  举报