二分法求最大值最小化或最小值最大化问题

本文探讨了两种经典算法问题——最小值最大化与最大值最小化问题的解决方案。前者通过二分查找和贪心策略实现了牛舍分配问题的最佳解答;后者同样采用二分查找来确定序列划分的最优方案。

1.最小值最大化

例题:

题目描述

   农夫约翰建造了一座有n(2<=n<=100000)间牛舍的小屋,牛舍排在一条直线上,第i间牛舍在xi(0<=xi<=1000000000)的位置,但是约翰的m(2<=m<=n)头牛对小屋很不满意,因此经常互相攻击,约翰为了防止牛之间互相伤害,因此决定把每头牛都放在离其它牛尽量远的牛舍。也就是要最大化最近的两头牛之间的距离。

   牛并不喜欢这种布局,而且几头牛之间就放在一个隔间里,它们就要发生争斗。为了不让牛互相伤害,约翰决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能大,那么,这个最大的最小距离是多少呢?

输入格式

  第一行是用空格分隔的两个整数n,m

  第二行为n个用空格隔开的整数,表示位置xi

输出格式

  输出仅一个整数,表示最大的最小距离值

样例输入

 5 3

 1 2 8 4 9

样例输出

 3

样例解释

  把牛放在第1,4, 8 间,这样最小的距离值是3

思路
  设C(d)表示可以安排牛的位置,并使得最近的两头牛的距离不小于d。

  那么问题就转化为求满足C(d)的最大的d,另外,最近的间距不小于d也可以看成是所有牛的间距都不小于d,因此就可以用C(d)表示可以安排牛的位置,并使得最近的两头牛的间距不小d

对这个问题,使用贪心可以容易求解:

  1.对牛舍的位置x进行排序

  2.把第一头牛放入牛舍x0

  3.如果第i头牛放入了xj间牛舍,则第i+1头牛就要放入满足xj+1<=xk的最小牛舍xk中。

参考代码

#include<stdio.h>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,x[N];
int check(int d)
{
   int cow=1,dis=x[1]+d;
   for(int i=2;i<=n;i++)
   {
       if(x[i]<dis) continue; //若x[i]<dis,说明该牛舍与前一个牛舍的距离小于最小距离值d
       cow++; dis=x[i]+d;
   }
   return  cow>=m;
}
int main()
{
    int i;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x[i]);
        }
        sort(x+1,x+n+1);
        int left=0,right=x[n]-x[1],mid;
        while(left<=right)
        {
            mid=(left+right)>>1; //mid为试图找到的最大的最小距离值
            if(check(mid))
                left=mid+1;
            else
                right=mid-1;
        }
        printf("%d\n",right);
    }
    return 0;
}

2.最大值最小化

例题:

问题描述

把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值最小是多少?

例如序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,那么最大值为7;

如果划分为 1 2 | 3 2 | 5 4,则最大值为9,不是最小。

输入格式

  第一行是用空格分隔的两个整数n,m

  第二行为n个用空格隔开的整数,表示序列中的数

输出格式

  输出仅一个整数,表示S(i)最大的最小值

样例输入

 6 3

 1 2 3 2 5 4

样例输出

 7

算法思路

要解决最大值最小化的问题,基本思路就是选取任意一个范围(输入数组的最大值到数组所有元素的和),然后在这个范围内进行二分法,每次把和范围的中间值mid当作最小值,然后判断在mid值下数组是否能够被分为m个部分

参考代码

#include<stdio.h>
#define MAX 10005
int n,m,a[MAX];
bool judge(int key)
{
    int sum=0,count=0,i;
    for(i=1;i<=n;i++)
    {
        sum+=a[i];
        if(sum>key)
        {
            sum=a[i];
            count++;
        }
    }
    if(count+1<=m)
       return 1;
    return 0;
}
void binary(int left,int right)
{
    while(left<right)
    {
        int mid=(left+right)/2;
        if(judge(mid))
          right=mid;
        else
          left=mid+1;
    }
    printf("%d\n",left);
}
int main()
{
    int i;
    while(~scanf("%d%d",&n,&m))
    {
        int left=0,right=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            right+=a[i];
            if(a[i]>left)
              left=a[i];
        }
        binary(left,right);
    }
    return 0;
}

 

<think> 我们正在讨论如何使用二分法查找最大护盾强度的问题。需要注意的是,护盾强度通常是一个在一定范围内变化的数值,我们需要找到一个最大的强度值,使得在该强度下护盾能够承受某种条件(例如攻击)而不破裂。这类似于在一个有序序列中查找满足特定条件的最大值问题。 二分查找法适用于解决在一个有序区间内查找满足条件的边界值的问题。在这个场景中,条件通常是“护盾是否能够承受”,而我们需要找到最大的能够承受的强度。 思路: 1. 确定搜索范围:[low, high],其中low可以是最小强度(例如0),high可以是最大强度(例如护盾设计上限一个足够大的值)。 2. 条件函数:定义一个函数check(x),用于判断当护盾强度为x时,是否能够承受特定条件(例如攻击)。如果能够承受,返回True;否则返回False。 3. 二分查找:在区间[low, high]中,我们希望找到最大的x,使得check(x)为True。因此,当check(mid)为True时,说明mid强度是可行的,那么最大强度可能在[mid, high]中;否则,在[low, mid-1]中。 具体步骤: a. 初始化:low=0, high=最大强度上限 b. 当low <= high时循环: mid = (low + high) // 2 if check(mid)为True:则最大强度至少为mid,所以low = mid + 1 else:则mid强度不可行,所以high = mid - 1 c. 循环结束时,high就是满足条件的最大值(因为当循环结束时,low=high+1,而high是最后一个满足条件的值)。 注意:为什么结果是high? 因为我们在每次check(mid)为True时,将low提高到mid+1,这样当循环结束时,low指向的是第一个不满足条件的强度,而high指向的是最后一个满足条件的强度。 因此,最大护盾强度就是high。 但是,我们需要确保初始的high足够大,能够覆盖可能的最大强度。同时,check函数的实现是关键,它需要根据具体问题来判断护盾在强度x下是否满足要。 示例伪代码: ``` def find_max_shield_strength(max_possible_strength, check_function): low, high = 0, max_possible_strength while low <= high: mid = (low + high) // 2 if check_function(mid): low = mid + 1 else: high = mid - 1 return high # 返回最大护盾强度 ``` 注意:如果有可能没有满足条件的强度(即连0强度都不满足条件),那么返回的high会是-1,因此在实际应用中需要检查这种情况。 引用:二分查找在求解最大值最小化最小值最大化问题应用广泛[^1]。 相关问题生成: 1. 如何设计护盾强度的check函数? 2. 二分查找算法的时间复杂度是多少? 3. 除了二分法,还有哪些方法可以用来求解最大护盾强度问题? </think> ### 使用二分法查找最大护盾强度的方法 在查找最大护盾强度的问题中,二分法是一种高效解决方案,尤其当护盾强度与承受能力之间存在单调关系时(即强度越大,承受能力越强)。以下是完整的实现方法: #### 核心思路 1. **单调性前提**:护盾强度 $s$ 与承受能力 $f(s)$ 必须满足: - $f(s)$ 在区间 $[min, max]$ 上单调递增 - 存在临界值 $s_{max}$ 使得: - $\forall s \leq s_{max}, f(s) = \text{true}$(能承受攻击) - $\forall s > s_{max}, f(s) = \text{false}$(不能承受攻击) 2. **二分法流程**: - **初始化**:设 $low = min\_strength$, $high = max\_strength$ - **迭代缩小区间**: - 计算中点 $mid = \lfloor (low + high)/2 \rfloor$ - 检测 $f(mid)$: - 若 $f(mid) = \text{true}$,则 $s_{max} \geq mid$,更新 $low = mid + 1$ - 若 $f(mid) = \text{false}$,则 $s_{max} < mid$,更新 $high = mid - 1$ - **终止条件**:当 $low > high$ 时,$high$ 即为最大护盾强度 #### 伪代码实现 ```python def find_max_shield_strength(min_strength, max_strength, check_function): low, high = min_strength, max_strength while low <= high: mid = (low + high) // 2 if check_function(mid): # 承受能力检测 low = mid + 1 # 强度可提升 else: high = mid - 1 # 强度需降低 return high # 返回最大有效强度 ``` #### 关键组件 1. **承受能力检测函数** `check_function(s)`: ```python def check_function(strength): # 模拟护盾承受攻击的物理计算 damage = simulate_attack() # 攻击伤害计算 return strength >= damage # 强度能否承受伤害 ``` *实际应用中可能涉及流体力学电磁场仿真[^1]* 2. **边界确定**: - $min\_strength$:护盾最小有效强度(如0) - $max\_strength$:理论最大强度(由材料属性决定) #### 复杂度分析 - **时间复杂度**:$O(\log n)$ $$T(n) = T(n/2) + O(1)$$ 其中 $n = max\_strength - min\_strength$ - **空间复杂度**:$O(1)$(无额外存储) #### 应用示例 假设护盾强度范围 $[0, 1000]$,临界值为 $s_{max}=732$: | 迭代次数 | low | high | mid | $f(mid)$ | 操作 | |----------|-----|------|-----|----------|-------------| | 1 | 0 | 1000 | 500 | true | low=501 | | 2 | 501 | 1000 | 750 | false | high=749 | | 3 | 501 | 749 | 625 | true | low=626 | | 4 | 626 | 749 | 687 | true | low=688 | | 5 | 688 | 749 | 718 | true | low=719 | | 6 | 719 | 749 | 734 | false | high=733 | | 7 | 719 | 733 | 726 | true | low=727 | | 8 | 727 | 733 | 730 | true | low=731 | | 9 | 731 | 733 | 732 | true | low=733 | | 10 | 733 | 733 | 733 | false | high=732→结果| 最终输出 $s_{max}=732$,仅需10次检测(暴力枚举需733次)[^2]。 --- ### 相关问题 1. 如何确定护盾强度检测函数 $f(s)$ 的物理模型? 2. 当护盾强度与承受能力非严格单调时,二分法是否仍然适用? 3. 二分法相比梯度下降法在优化护盾参数时有何优劣? 4. 如何验证找到的最大护盾强度是全局最优解? 5. 在分布式系统中如何并行化护盾强度检测? [^1]: 护盾强度计算通常涉及麦克斯韦方程组和流体动力学仿真 [^2]: 二分查找的复杂度证明参见《算法导论》第3版第12章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值