125.耍杂技的牛
题意理解: 将牛牛进行排序, 使得最大风险值是最小的, 也就是得到一种排序, 能将最大风险值降低.
这道题我有一种错误的思路:
我的思路:
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。
-
每种情况风险值的最大值都是最底下的牛的风险值
-
所以要挑选最底下的牛, 在某一种挑选方案下, 最底下的这头牛的风险值比其他牛做最底层牛的风险值小, 这个最小值就是结果
-
风险值 = w1 + ... + wn-1 - Sn = ∑Wi - Wn - Sn = ∑Wi - (Wn + Sn)
可以看出应该选w和s相加最大的牛放在最底下
证明:
-
第一句话可以证明:
反证法: 如果是中间某一头牛的风险值是最大值, 则可以把它交换到最底层, 风险值继续增大, 所以说, 最底层的牛的风险值最大
我的思路可以调试, 但是不能过ac, 还没想好是怎么回事, 目前觉得应该是我先求了最大值, 将最大值固定在最底部的牛, 实际上题目的要求是需要将风险值降低, 之后再求最大值, 此时, 最大值可能是在牛牛的中间层数出现!! t对于题意理解的的有问题
代码
#include <iostream>
#include <algorithm>
//贪心 推公式 耍杂技的牛 这个思路可以通过调试, 但是不能ac, 题意的理解有问题
using namespace std;
const int N = 50010;
int n;//牛的数量
int w[N];
int s[N];
int main() {
scanf("%d", &n);//输入牛数量
int max_sum = 0;//w和s之和
int sum = 0;//所有牛的重量的和
for (int i = 1; i <= n; i++)
scanf("%d %d", &w[i], &s[i]), sum += w[i], max_sum = max(max_sum, w[i] + s[i]);
int res = -2e9;//风险值结果
//把max_sum放最底下就是对的
res= sum - max_sum;//∑Wi - (Sn + Wn)
printf("%d\n", res);
return 0;
}
正确的思路:
-
按照Wi+Si从小到大的顺序排, 最大的危险系数一定是最小的, 在这个序列中排序里面的风险值
证明:
-
贪心得到的答案(一种方案) >= 最优解ans, 成立
-
贪心得到的答案 <= 最优解.
假设最优解不是按照Wi+Si从小到大排序的, 即, 存在相邻两头牛, 使得 wi + si > wi+1 + si+1
把这两头牛交换, 得到:
i位置的牛 i+1位置的牛 交换前风险 w1 + ... + w(i-1) - si w1 + ...+ wi - s(i+1) 交换后 w1 + ... + w(i-1) - s(i+1) w1+...+ w(i-1) + w(i+1) - si i位置的牛 i+1位置的牛 交换前风险 - si wi - s(i+1) 交换后 - s(i+1) w(i+1) - si 都加上si + s(i+1)
i位置的牛 i+1位置的牛 交换前风险 s(i+1) wi + si 交换后 si w(i+1) + s(i+1) wi + si > si, wi + si > w(i+1) + s(i+1) 所以交换后两个数的风险值的最大值是变小的
所以只要有逆序, 经过几次交换, 必然可以交换成两数之和从小到大排序
代码:
#include <iostream>
#include <algorithm>
//贪心 推公式 耍杂技的牛
using namespace std;
typedef pair<int, int> PII;//要整体排序, j就把两个数组整体存到pair
const int N = 50010;
int n;//牛的数量
//int w[N], s[N];
PII cow[N];//w和s组合起来
int main()
{
scanf("%d", &n);//输入牛数量
for (int i = 0; i < n; i++) {
int w, s;//pair的两个参数
scanf("%d%d", &w, &s);
cow[i] = {w + s, w};//
}
//排序
sort(cow, cow + n);//pair排序, 按值从小到大
int res = -2e9, sum = 0;//所有牛的重量的和
for (int i = 0; i < n; i++)
{
int w = cow[i].second, s = cow[i].first - w;
res = max(res, sum - s);
sum += w;
}
printf("%d\n", res);
return 0;
}