You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 125. 耍杂技的牛

一、题目描述

农民约翰的 N 头奶牛(编号为 1..N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。

奶牛们不是非常有创意,只提出了一个杂技表演:

叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。

奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。

N 头奶牛中的每一头都有着自己的重量 W_i 以及自己的强壮程度 S_i

一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为 风险值,风险值越大,这只牛撑不住的可能性越高。

您的任务是 确定奶牛的排序,使得所有奶牛的风险值中的 最大值尽可能的小

输入格式 第一行输入整数 N,表示奶牛数量。

接下来 N 行,每行输入两个整数,表示牛的重量和强壮程度,第 i 行表示第 i 头牛的重量 W_i 以及它的强壮程度 S_i

输出格式 输出一个整数,表示最大风险值的最小可能值。

数据范围 1≤N≤50000, 1≤W_i≤10,000, 1≤S_i≤1,000,000,000

输入样例

3
10 3
2 5
3 3

输出样例

2

二、算法思路

假设所有牛的顺序已排好,我们把第i头牛和第i+1头牛的位置互换一下,看看会发生什么情况:

交换前 交换后
i \sum_{j=1}^{i-1}w_j-s_i$$ \sum_{j=1}^{i-1}w_j+w_{i+1}-s_i$$
i+1 \sum_{j=1}^{i}w_j-s_{i+1} \sum_{j=1}^{i-1}w_j-s_{i+1}

其他牛的危险值显然不变,所以分析交换前后这两头牛中最大的危险值即可。 将上述式子进行化简,四个式子每个减去

\sum_{j=1}^{i-1}w_j

得到:

交换前 交换后
i -s_i w_{i+1}-s_i
i+1 w_{i}-s_{i+1} -s_{i+1}

\because s,w都是正数 \therefore w_i-s_{i+1}>-s_{i+1},w_{i+1}-s_i>-s_i

所以,交换前后的最大值,就是在比较 w_i-s_{i+1},w_{i+1}-s_i

  • w_i-s_{i+1}>=w_{i+1}-s_i,即w_i+s_i>=w_{i+1}+s_{i+1}时,交换后更优

  • w_i-s_{i+1}<w_{i+1}-s_i,即w_i+s_i<w_{i+1}+s_{i+1}时,交换前更优

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

三、完整代码

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 50010;
PII cow[N];
int n;

int main() {
    cin >> n;           //奶牛的数量
    for (int i = 0; i < n; i++) {
        int s, w;                         //牛的重量和强壮程度
        cin >> w >> s;
        cow[i] = {w + s, w};            //之所以这样记录数据,是因为我们找到贪心的公式,按 wi+si排序
    }
    //排序
    sort(cow, cow + n);

    //最大风险值
    int res = -INF, sum = 0;
    for (int i = 0; i < n; i++) {
        int s = cow[i].first - cow[i].second, w = cow[i].second;
        res = max(res, sum - s); //res为最大风险值
        sum += w;                //sum=w1+w2+w3+...+wi
    }
    printf("%d\n", res);
    return 0;
}