问题描述
Lazy有N个礼物需要打成M个包裹,邮寄给M个人,这些礼物虽然很便宜,但是很重。Lazy希望每个人得到的礼物的编号都是连续的。为了避免支付高昂的超重费,他还希望让包裹的最大重量最小。
输入格式
一行两个整数N和M。
一行N个整数,表示N个礼物的重量。
输出格式
一个整数,表示最小的最大重量。
样例输入
3 2
1 1 2
1、解题思路
共有N个礼物,需要进行M次打包,希望让每个人得到的包裹连续且最大重量最小,假设所有礼物的总重量为sum ,所有礼物中最重的礼物为max ,那么答案只有能可能出现[max,sum] 这个区间内部,我们可以给定一个属于区间[max,sum]的一个重量 t a r g e t target target为每个包裹可以装入的最大重量。
那么我们如何判断 t a r g e t target target最大重量下能够进行M次打包呢?因为打包的礼物必须是连续的,因此从第一个礼物开始遍历,看看最大重量 t a r g e t target target下 N 个礼物需要打多少个包,如果小于等于M,说明每个包最大重量为 t a r g e t target target是能够装下,符合题意。题目要求尽量获得最小的重量,这里使用二分的方法,左区间:max,右区间:sum,封装函数 j u d g e judge judge判断能够打包 ,取区间中间值mid,如果judge判断为true,说明mid下能满足题意,right=mid,否则left=mid+1,直到遍历出结果
2、代码
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int num = cin.nextInt();
int pack = cin.nextInt();
int []weight=new int[num];
int right=0,left=0;
for(int i=0;i<num;++i){
weight[i]=cin.nextInt();
right+=weight[i];
}
int mid=0;
//二分查找
while(left<right){
mid=(left+right)/2;
if(judge(weight,mid,pack)){
right = mid;
}
else{
left=mid+1;
}
}
System.out.println(left);
}
private static boolean judge(int[] weight, int mid,int pack) {
//curWeight 保存当前这个包的重量
int curWeight=0;
//curPack 保存的需要打包数量
int curPack=1;
for(int val:weight){
// 如果超出了所给定的最大打包数量,返回false
if(val>mid) {
return false;
}
curWeight+=val;
// 超过了单个包的最大重量,打一个新的包
if(curWeight>mid){
curWeight=val;
curPack+=1;
}
}
return curPack<=pack;
}
}