P3132 [USACO16JAN] Angry Cows G 题解

该文描述了一个计算最小力度以覆盖所有干草堆的问题,采用二分搜索算法,在给定的上下界内寻找合适的力度值。在每次迭代中,通过暴力判断当前力度是否可行,通过区间扩散检查能否从中间位置波及到所有干草堆。如果不可行,则调整力度边界,直到找到满足条件的最小力度。
摘要由CSDN通过智能技术生成

求得是最小力度R,R最大显然不超过最左边干草堆与最右边干草堆的距离。

有了下界(0)和上界,容易想到二分(估计很多人考场上都想到了)

二分力度,并判断是否可行。

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    double l=0,r=1.0*(a[n] - a[1])/2;
    int bash = 70;
    while(r-l>eps && --bash)
    {
        double mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.1lf",l);

实数域二分可以限制批次,1e9范围70次完全够。

eps是精度,我设置为1e-7。

然后重点是如何判断方案可行。

答案是:暴力判断。

二分下包你要打哪里,lower_bound得到左边和右边最靠近的干草堆。

然后暴力的向左和向右扩散,得到你最左边炸到哪和最右边炸到哪。

如果左右都无法扩散到边界,则这个力度不可能。

如果只是其中一边无法扩散到,那就把 mid 往那边移动。

如图:

所以我们暴力的去判断可行性。

bool check(double k)
{
    double l = a[1], r = a[n];
    int bash = 70;
    while (r - l > eps && --bash)
    {
        double mid = (l + r) / 2;
        bool f1, f2;
        f1 = f2 = true;
        //左边和右边能否到达
        int pos = lower_bound(a + 1, a + 1 + n, mid) - a; //显而易见
        int left = pos - 1, right = pos;                     //左边和右边
        double now = mid, force = k;                         //打在哪以及力度
        while (left > 0)
        {
            if (now - a[left] > force) //打不到
            {
                f1 = false;
                break;
            }
            while (left > 0 && now - a[left] <= force) //能以force的力波及到最远距离
            {
                left--;
            }
            now = a[left + 1], force--; //题目要求
        }
        now = mid, force = k;
        while (right <= n) //类似
        {
            if (a[right] - now > force)
            {
                f2 = false;
                break;
            }
            while (right <= n && a[right] - now <= force)
            {
                right++;
            }
            now = a[right - 1], force--;
        }
        if (!f1 && !f2)
        {
            return false;
        }
        if (!f1)
        {
            r = mid;
        }
        else if (!f2)
        {
            l = mid;
        }
        else
        {
            return true;
        }
    }
    return false;
}

然后就Accepted了。

代码都给出了,改不 Accepted 就离谱了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值