【Acwing算法基础课】第六章贪心-推公式-125.耍杂技的牛

125.耍杂技的牛

题目: 125. 耍杂技的牛 - AcWing题库

题意理解:  将牛牛进行排序, 使得最大风险值是最小的, 也就是得到一种排序, 能将最大风险值降低.


这道题我有一种错误的思路:

我的思路:

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

  1. 每种情况风险值的最大值都是最底下的牛的风险值

  2. 所以要挑选最底下的牛, 在某一种挑选方案下, 最底下的这头牛的风险值比其他牛做最底层牛的风险值, 这个最小值就是结果

  3. 风险值 = w1 + ... + wn-1 - Sn = ∑Wi - Wn - Sn = ∑Wi - (Wn + Sn)

    可以看出应该选w和s相加最大的牛放在最底下

证明:

  1. 第一句话可以证明:

    反证法: 如果是中间某一头牛的风险值是最大值, 则可以把它交换到最底层, 风险值继续增大, 所以说, 最底层的牛的风险值最大

我的思路可以调试, 但是不能过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;
}

正确的思路:

  1. 按照Wi+Si从小到大的顺序排, 最大的危险系数一定是最小的, 在这个序列中排序里面的风险值

证明:

  1. 贪心得到的答案(一种方案) >= 最优解ans, 成立

  2. 贪心得到的答案 <= 最优解.

    假设最优解不是按照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;
}

猜你喜欢

转载自blog.csdn.net/weixin_65293439/article/details/128473995