贪心-耍杂技的牛

发布于:2024-05-05 ⋅ 阅读:(27) ⋅ 点赞:(0)

问题描述

农民约翰的 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

输入样例

3
10 3
2 5
3 3

输出样例

2

问题分析

通过题目,我们知道每头牛的危险值=它上面牛的重量之和-自身的强壮值。
要使每头牛的危险值最小,根据贪心思想:

  • 自身w值越大应该放到底部(即减小上面式子中的被减数)
  • 自身s值越大应该放到底部(即增大上述中的减数);
    所以每头牛的(w+s)值越大应该排在后面,即升序排序。

数学分析证明:
在这里插入图片描述
交换之前其他牛的危险值不变

  • i之前的牛并不涉及牛i与i+1的重量值。
  • i+1之后的牛只涉及到牛i与i+1重量值的和

所以交换分析前后这两头牛中最大的危险值即可。
将上述式子进行化简,得到下面的式子
在这里插入图片描述
由于s,w都是整数,wi-si+1>-si+1,wi+1-si>-si;比较wi-si+1,wi+1-si即可

  • 当wi-si+1>=wi+1-si,即wi+si>=wi+1+si+1时,交换后更优
  • 当wi-si+1<wi+1-si,即wi+si<wi+1+si+1时,交换前更优

所以得到做法:按每头牛的w+s进行排序。
然后根据题意算出每头牛的危险值记录其中的最大值即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=50010;
typedef pair<int,int> PII;
PII cow[N]; // 定义一个pair类型的数组,用于存储牛的重量和能力值
int n; // 牛的数量
int main()
{
    cin>>n; // 输入牛的数量
    for(int i=0;i<n;i++)
    {
        int w,s; // w表示牛的重量,s表示牛的能力值
        cin>>w>>s; // 输入每头牛的重量和能力值
        cow[i]={w+s,w}; // 将每头牛的重量和能力值存入数组中
    }
    sort(cow,cow+n); // 对数组进行排序,按照重量和能力值的和从小到大排序
    int res=-2e9,sum=0; // res表示结果,sum表示当前牛的总重量
    for(int i=0;i<n;i++)
    {
        int s=cow[i].first-cow[i].second,w=cow[i].second; // 计算当前牛的能力值和重量
        res=max(res,sum-s); // 更新结果
        sum+=w; // 更新总重量
    }
    cout<<res<<endl; // 输出结果
    return 0;
}