Cow Acrobats(这是我做的最顺的一道二分,虽然也wa了两发……)

题目链接:https://cn.vjudge.net/contest/279225#problem/F

题目大意:就是一群牛他们要一个接一个的摞高,问该群牛最大的倒塌风险最小是多少。就是一个最大值的最小化问题。

思路:定义一个结构体用来存每头牛的信息。然后每头牛的倒塌风险是它上面的牛的总重量-自身的力量,也就是wtotal-s,假设它与它上面的牛为一个整体,总重为sum_w,那么对于这头牛的危险值为sum_w-w-s,要想sum_w-(w+s)的值最小,w+s的值就应该最大,由此可见取最优化,wi+si越大越应该在下面。
还有一种想法就是,假设当前的序列是最优的。任意相连的两头牛假设信息分别是w1,s1,w2,s2.然后上边的牛的上边的牛的重量为sum,然后上边这头牛的危险值就是r1=sum-s1,下边的牛的危险值就是,r2=sum+w1-s2.现在使两者换位置,下边的牛变为了rr1=sum+w2-s1,上边的牛rr2=sum-s2.因为之前的是最优的,所以对于下边那头牛的就是r2<=rr1整理一下也就是
w1+s1<=w2+s2,所以重量和力量越大的应该越在下面才最优。

其实这道题可以不用二分,因为排好牛的位置之后,每头牛的危险值就确定了然后就直接算每头牛的危险值的时候就和max_比较交换就行了。
二分的时候需要注意的就是要把min_设为无穷小,因为危险值可能是负的

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
ll max_,min_,mid;
struct node
{
    ll w;
    ll s;
    ll r;
    ll wtotal;//这个是该头牛上面的牛的总重量
};
node a[50005];
ll N;
bool cmp(const node &node1,const node &node2)
{
    return (node1.w+node1.s)<(node2.w+node2.s);//从小到大排序
}
bool judge(ll x)
{
    ll summ=0;
    for(ll i=0;i<N;i++)
    {
        if(a[i].r>x)
            summ++;
    }
    return summ>0;//有大于的就是不可行
}
int main()
{
    while(~scanf("%lld",&N))
    {
        //memset(&a,false,sizeof(a));
        for(ll i=0;i<N;i++)
        {
            scanf("%lld%lld",&a[i].w,&a[i].s);
            a[i].r=0;
            a[i].wtotal=0;
        }
        sort(a,a+N,cmp);
        ll sum=0;
        for(ll i=0;i<N;i++)
        {
            sum+=a[i].w;
            a[i].wtotal=sum-a[i].w;
            a[i].r=a[i].wtotal-a[i].s;
        }
        max_=sum;
        min_=-INF;//我开始就是赋的0,然后就wa了
        while(max_>=min_)
        {
            mid=(max_+min_)/2;
            if(judge(mid))//最大值的最小化问题,可行往左取,不可行往右取,右区间可行,左区间不可行
                min_=mid+1;
            else
                max_=mid-1;
        }
        printf("%lld\n",min_);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/86552706