二分最化最值问题

Posted Roni

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分最化最值问题相关的知识,希望对你有一定的参考价值。

二分最化最值问题

把一个包含n个正整数的序列划分成m个连续的子序列(每个正整数恰好属于一个序列).

设i个序列的各数之和为s(i).你的任务是让所有s(i)的最大值尽量小.

这个算法很有现实意义.给你一堆乱七八糟的东西分堆,分出来的东西都不超过一个固定的数值,这是需要技术含量的喔.



1.首先确定二分的上下界,这是每次二分必须做的准备工作.在这里上限是这一堆东西的总量,下限是单个最大物品的值.


2.确定上下限之后开始二分.即判断当前分堆是否合理,再判断分堆是否合理中,主要限制因素为两个,一个是单堆的量肯定不能超过当前的mid值,另一个是分出的堆数一定不能超过题目要求的m值.


3.由判断条件即可将二分范围进行缩小,即一旦当前mid值满足分堆要求,意味着我还可以把mid值缩小(最小化),即把二分的right=mid,如果当前mid值触犯了判断条件,就把left=mid.


4.由以上二分return
的结果即为所求值.

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
int ok(int m)
{
    int sum=0,cnt=0;
    for(int i=0;i<n;i++)
    {
        if(a[i] > m) return false;
        
        if(sum + a[i] > m)
        {
            cnt++;
            sum = a[i];
        }
        else sum+=a[i];
    }
    return cnt <= m;
}
int main()
{
    int n,k,sum=0;
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        sum+=a[i];          //r
        Max=max(Max,a[i);   //l
    }
    int l=Max,r=sum;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(ok(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;
}

最小化最大值


和最大化最小值问题正好相反,同样用二分解决,差别主要在判断条件.


1.最大化最小值(兼济天下)

相当于把n个东西分给m个人,使得每个人至少拿x个,那么每个人拿够了就走,给后面的人多留一点,只要能分够>=m个人就是true,多的全扔给最后一个人就是了.

2.最小化最大值(独善其身)


相当于n个东西分给m个人,每个人至多拿x个 ,那么每个人尽可能拿多一点,给后面的人少留一点,只要能使<=m个人分完n个东西就是true,之后每个人随便拿一点给没有拿到的人就是了.


注意:


1.关于初始值,有些题目直接给前缀和,那样最小值的最大值就是平均值,最大值的最小值也是平均值
对于可以计算sum的题有:

2.最大化最小值:

x为单点最小值,y为平均值.

3.最小化最大值:

x为平均值与单点最大值两者中大的那一个,y为sum.其实直接令x=0,y=0x7fffffff即可,不过循环32次而已...

以上是关于二分最化最值问题的主要内容,如果未能解决你的问题,请参考以下文章

51nod1287(二分/线段树区间最值&单点更新)

遇到「最值问题」还在无脑动态规划?二分法考虑一下呗

NKOJ2325: 二分与分治:区间最值

hdu6070(分数规划/二分+线段树区间更新,区间最值)

模板动态最值

如何使用 OpenMP 并行化最近邻搜索