数组分段和最大值最小问题

参考博文:https://blog.csdn.net/u011947630/article/details/81606259
参考博文:https://blog.csdn.net/jal517486222/article/details/86491440
原始问题:
假设有m个房间,清洁每个房间耗时用一个数组表示,10、20、30、40、50、60、70、80、90,安排n个清洁工,将连续的房间分成n份,每部分耗时求和,其最大值为此种分法的总耗时。求最快的耗时是多少。例如3个清洁工的话,10 20 30 40 50 | 60 70 | 80 90,此时是最快的,耗时为170。

分析:
此题可以想象成把数据按顺序装入桶中,m即是给定的桶数,问桶的容量至少应该为多少才能恰好把这些数装入n个桶中(按顺序装的)。

二分法思想求解:
首先我们可以知道,桶的容量最少不会小于数组中的最大值,即桶容量的最小值(小于的话,这个数没法装进任何桶中),假设只需要一个桶,那么其容量应该是数组所有元素的和,即桶容量的最大值;其次,桶数量越多,需要的桶的容量就可以越少,即随着桶容量的增加,需要的桶的数量非递增的(二分查找就是利用这点);我们要求的就是在给定的桶数量m的时候,找最小的桶容量就可以把所有的数依次装入k个桶中。在二分查找的过程中,对于当前的桶容量,我们可以计算出需要的最少桶数requiredPainters,如果需要的桶数量大于给定的桶数量k,说明桶容量太小了,只需在后面找对应的最小容量使需要的桶数恰好等于k;如果计算需要的桶数量小于等于k,说明桶容量可能大了(也可能正好是要找的最小桶容量),不管怎样,该桶容量之后的桶容量肯定不用考虑了(肯定大于最小桶容量),这样再次缩小查找的范围,继续循环直到终止,终止时,当前的桶容量既是最小的桶容量。

import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int k = cin.nextInt();
        int[]a = new int[n];
        int left = 0, right = 0;
        for (int i = 0; i < n; i++){
            a[i] = cin.nextInt();
            //应在left和right中间寻找满足条件的桶的容量
            left = Math.max(left, a[i]);
            right += a[i];
        }

        //mid值就是表示的桶的容量
        int mid;
        while(left < right){
            mid = (left + right) >> 1;
            //System.err.print("left="+left+",right="+right+",mid="+mid);
            //t表示桶的数量
            int t = 1, sum = a[0];
            for(int i = 1; i < n; i++){
                if(sum + a[i] <= mid){
                    sum += a[i];
                    //System.out.print(",sum="+sum);
                }else{
                    //桶数加一,从a[i]开始重新开始往桶里放元素
                    t++;
                    if(t > k)break;
                    sum = a[i];
                }
            }
            //System.err.println(",t="+t);
            if(t > k){
                //t>k说明所需的桶的数量超出了给定的范围,应通过提高桶的容量来降低桶的数量
                left = mid + 1;
            }else{
                //两种情况:
                //1、t<k说明桶的容量太大了,应降低桶的容量来达到给定的桶的数量
                //2、t=k达到了规定的桶的数量,此时right左移求满足条件的桶的容量的最小值
                right = mid;
            }
        }
        System.out.println(right);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值