poj 3045

/*
    题意:
        给定n,然后是n头牛,每头牛有一个重量w,力量s
        要求把n头牛一个叠在一个头上,类似叠罗汉
        对于一个叠罗汉的序列,每头牛的risk是它顶上的牛的重量之和减去它的s
        对于序列的最大的risk就是这个序列的risk
        问如何确定一种序列使得risk最小
    解析:
        首先要想到,对于相邻的两头牛,交换它们的位置,仅仅会影响他们两个的risk值
        然后,对于最优系列的相邻的两头牛
        w1 s1
        w2 s2
        最顶上的那头的顶上的牛的质量和为sum
        那么第一头牛的risk就是 sum - s1   r1
        第二头的为sum + w1 - s2           r2

        假如交换位置之后:
            sum - s2                      r3
            sum + w2 - s1                 r4
        有:max(r1,r2) < max(r3,r4)——r1..r4分别对应四个risk

        那么,有四种假设:
            r1 < r3
            r1 < r4
            r2 < r3
            r2 < r4
        当然这四个假设,每一个都还隐含了两个不等式,在这里先不写出来
        因为明显有 r1 < r4 r2 > r3
        所以,只剩下:
            1.r1 < r3 —— r1 > r2 && r3 > r4
            2.r2 < r4 —— r2 > r1 && r4 > r3

        对于1:
            s2 - s1 > w1 && s1 - s2 > w2,因为w1,w2都大于0,所以不符合。
        所以只剩下2
            得到:w1 + s1 < w2 + s2
        综上,得出w+s最大的必定在最底下,按照w+s排序得到的就是最优序列。


        顺便,要注意一下,risk是可以为负数的,所以初始化的时候不可以为0。
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#define range(i,a,b) for (int i=a;i<=b;i++)

const int maxn = 50000;

typedef long long ll;

using namespace std;

struct Data
{
    ll w,s;
    friend bool operator < (const Data &a,const Data &b)
    {
        return a.w+a.s < b.w + b.s;
    }
};

ll n;
Data dat[maxn+1];

void input(ll &a)
{
    scanf("%I64d",&a);
}

int main()
{
    input(n);
    range(c,1,n)
    {
        input(dat[c].w);
        input(dat[c].s);
    }

    sort(dat+1,dat+1+n);

    ll sum(0);
    ll risk=-(1<<29);
    //初始化状态为0的话,就会WA!

    range(i,1,n)
    {
        risk = sum - dat[i].s > risk ? sum - dat[i].s : risk;
        sum += dat[i].w;
    }

    cout<<risk<<endl;

    return 0;
}
原文地址:https://www.cnblogs.com/dandi/p/4068787.html