二分答案算法笔记

文章介绍了如何使用二分法来解决寻找‘最大值的最小’或‘最小值的最大’的问题。在有界且单调的解区间内,通过不断二分缩小范围,找到最优解。文中给出了二分法的框架,并通过求解最短距离最大值和分巧克力问题的实例来说明二分法的应用。

1、处理“最大值的最小”或者“最小值的最大”

二分答案条件:答案有界且答案单调,即答案在一个单调必区间内

二分答案作用:二分一般用来解决最优解问题。一个由可行解和非法解组成的闭区间,最优解一定可行,但可行解不一定最优。我们假设整个序列具有单调性,且一个数x为可行解,那么一般的,所有的x'(x'<x 或 x'>x)都是可行解。并且,如果有一个数y是非法解,那么一般的,所有的y'(y'>y 或 y'<y)都是非法解

使用场合:题目规定求“最大值的最小”或者“最小值的最大”

如下是求“最小值的最大”问题时二分框架


int l = 1;    //l和r分别代表二分的左边界和右边界
int r = maxx;
int ans,mid;
while (l <= r){
        mid = (l+r) / 2;
        if (judge(mid)){
            ans = mid;
            l = mid + 1;  //继续向mid右边找可能的最优解
        }
        else
            r = mid - 1;  //向mid左边找可行解
    }
    cout << ans << endl;  //最终输出最优解

如上题,最短距离尽可能长==求最小距离的最大值

我们二分跳跃距离,然后把这个跳跃距离“认为”是最短的跳跃距离,然后去以这个距离为标准移石头。使用一个judge判断这个解是不是可行解。如果这个解是可行解,那么有可能会有比这更优的解,那么我们就去它的右边二分。为什么去右边?答案是,这个区间是递增的 ,而我们求的是最短跳跃距离的最大值,显然再右边的值肯定比左边大,那么我们就有可能找到比这更优的解,直到找不到,那么最后找到的解就有理由认为是区间内最优解。反过来,如果二分到的这个解是一个非法解,我们就不可能再去右边找了。因为性质,右边的解一定全都是非法解。那么我们就应该去左边找解

judge函数每个题有每个题的写法,但大体上的思想应该都是一样的——想办法检测这个解是不是合法。拿这个题来说,我们去判断如果以这个距离为最短跳跃距离需要移走多少块石头,先不必考虑限制移走多少块,等全部拿完再把拿走的数量和限制进行比对,如果超出限制,那么这就是一个非法解,反之就是一个合法解

2、根据题目条件二分答案

如上题,答案范围在-100到100,且解之间绝对值>=1,我们可以二分每个1区间,通过f(x1)*f(x2)<0条件确定解所在区间,继续二分该区间。注意,由于二分的答案不为整数,所以要设置精度避免二分一直进行


    for (i=-100;i<100;i++)
    {
        l=i; 
        r=i+1;
        x1=fc(l); 
        x2=fc(r);
        if(!x1) 
        {
            printf("%.2lf ",l); 
            s++;
        }      //判断左端点,是零点直接输出。
                        
                        //不能判断右端点,会重复。
        if(x1*x2<0)                             //区间内有根。
        {
            while(r-l>=0.001)                     //二分控制精度。
            {
                m=(l+r)/2;  //middle
                if(fc(m)*fc(r)<=0) 
                   l=m; 
                else 
                   r=m;   //计算中点处函数值缩小区间。
            }
            printf("%.2lf ",r);  
            //输出右端点。
            s++;
        }
        if (s==3) 
            break;             
            //找到三个就退出大概会省一点时间
    }

 3、分巧克力

#include<bits/stdc++.h>
using namespace std;

const int maxx = 1e5 + 10;
struct Chocolate {
    int h, w;
};
vector<Chocolate> chocolate;
int n, k;

int cal(int num) {
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        cnt += (chocolate[i].h / num) * (chocolate[i].w / num);
    }
    return cnt;
}

int main()
{
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        int h, w;
        cin >> h >> w;
        chocolate.push_back({ h,w });
    }

    int l = 1, r = 1e5;         // r初始为可能的最大的答案        
    int mid;
    int ans = -maxx;
    while (l <= r) {            // 二分条件
        mid = (l + r) / 2;
        if (cal(mid) < k) {
            r = mid - 1;
        }
        else if (cal(mid) >= k) {
            l = mid + 1;
            ans = (ans,mid);    // 满足条件时,需要把答案记录下来
        }
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值