文章目录
0. 前言
我个人认为,贪心问题和数学式子密切相关。先有贪心思路,再简单写出式子,重点在于式子的正确性证明。大多都是不等式的方式证明等式,而不等式又牵扯到了各类的均值、调和、绝对值不等式等等,相当有意思 😦
1. 公式推导+贪心
样例模拟:
危险系数:上面所有牛的重量之和减去自己的强壮值
重量w 强壮值s 危险系数
3 3 0-3=-3
2 5 3-5=-2
10 3 3+2-3=2 最大危险系数小,为2
贪心思路:
- 按照 w i + s i w_i+s_i wi+si 从小到大的顺序排,最大的危险系数一定是最小的
证明:
- 从两个方面证明,贪心答案等于最优解:
- 贪心得到的答案一定大于等于最优解。因为最优解是所有方案的最小值,则贪心答案一定大于等于最优解
- 贪心得到的答案一定小于等于最优解
- 如果最优解不是按照
w
i
+
s
i
w_i+s_i
wi+si 从小到大排序的。那么一定存在相邻两头牛,满足
w
i
+
s
i
>
w
i
+
1
+
s
i
+
1
w_i+s_i > w_{i+1}+s_{i+1}
wi+si>wi+1+si+1
第 i 头牛 第i+1头牛 交换前危险系数 w1+w2+...+w(i-1)-si w1+w2+...+w(i-1)+wi-s(i+1) 交换后危险系数 w1+w2+...+w(i-1)-s(i+1) w1+w2+...+w(i-1)+w(i+1)-si 由于都有 w1+w2+...+w(i-1),则可以去掉,则为 交换前危险系数 -si wi-s(i+1) 交换后危险系数 -s(i+1) w(i+1)-si 给这四个数,统一加上 si+s(i+1),能好理解些 交换前危险系数 s(i+1) wi+si 交换后危险系数 si w(i+1)+s(i+1) 由于每个 wi、si 都是严格大于等于1的,那么 wi+si > si 恒成立 已知 w(i+1)+s(i+1) < wi+si 那么交换后 si、w(i+1)+s(i+1) 均严格小于 wi+si,故也严格小于交换前的 s(i+1)、wi+si 的最大值 那么说明,交换后其余牛位置不变,交换前后会使这两个牛的危险系数最大值变小 故,若最优解出现了逆序关系,则可以交换,且交换后最优解不会变大,直至变成有序的序列,最后等于贪心序列 那么在这个过程中,由于最优解交换后不会变大,可能不变和变小,交换重点为贪心序列,则贪心答案一定小于等于最优解 故,证得 贪心答案等于最优解
- 如果最优解不是按照
w
i
+
s
i
w_i+s_i
wi+si 从小到大排序的。那么一定存在相邻两头牛,满足
w
i
+
s
i
>
w
i
+
1
+
s
i
+
1
w_i+s_i > w_{i+1}+s_{i+1}
wi+si>wi+1+si+1
本题还是很难的贪心问题,但是很经典…貌似是 2012 年 NOIP
提高组的题目。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 5e5+5;
int n;
PII cow[N];
int main() {
cin >> n;
for (int i = 0; i < n; ++i) {
int w, s;
cin >> w >> s;
cow[i] = {w + s, s};
}
sort(cow, cow + n);
int res = -2e9, sum = 0;
for (int i = 0; i < n; ++i) {
int w = cow[i].first - cow[i].second, s = cow[i].second;
res = max(res, sum - s);
sum += w;
}
cout << res << endl;
return 0;
}