#蓝桥#JAVA#分巧克力
问题描述
儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi×Wi的方格组成的长方形。为了公平起见,
小明需要从这N块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
-
形状是正方形,边长是整数;
-
大小相同;
例如一块6×5的巧克力可以切出6块2×2的巧克力或者2块3×3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
思路解析:
采用二分查找(二分法)来确定满足条件的最大正方形边长。二分查找适用于在一个有序的数值范围内查找满足特定条件的数值,这里的有序范围是正方形边长的可能取值范围。
首先,读取两个整数 n
和 k
,分别表示巧克力的数量和需要分给的人数。
循环 n
次,每次读取两个整数,分别存储到 h
数组和 w
数组中,代表每块巧克力的高度和宽度。
接着,进入 while
循环,只要 min
小于等于 max
,就继续查找:
- 计算中间值
ave
:计算当前查找范围的中间值ave = (max + min) / 2
,作为当前尝试的正方形边长。 - 计算当前边长下的巧克力块数
cut
:- 初始化
cut
为 0。 - 遍历每块巧克力,对于每块巧克力,计算其在边长为
ave
时能切出的正方形小块数(h[i] / ave) * (w[i] / ave)
,并累加到cut
中。
- 初始化
- 根据
cut
的值调整查找范围:- 如果
cut
小于k
,说明当前边长ave
太大,切出的巧克力块数不够分给k
个人,将max
更新为ave - 1
,缩小查找范围到较小的边长。 - 如果
cut
大于等于k
,说明当前边长ave
可以满足要求,将min
更新为ave + 1
,继续在更大的边长范围内查找,并将ans
更新为ave
,记录当前符合要求的最大边长。
- 如果
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int n = scan.nextInt();
int k = scan.nextInt();
int[] h=new int[n];
int[] w=new int[n];
for (int i = 0; i <n ; i++) {
h[i] = scan.nextInt();
w[i] = scan.nextInt();
}
//设置所切块数的最大边界max和最小边界min
int max=100000;
int min=1;
int ave;//二分法的中间值
int cut=0;//所切的块数
int ans=0;//切出后,每块巧克力最大边长
//采用二分法,当min>max跳出循环
//取最大边界和最小边界的平均值(ave)代入循环,while(max>=min)
while (min<=max){
ave=(max+min)/2;
cut=0;
//循环,多少个n循环多少次,记录所切数目cut
for (int i = 0; i <n ; i++) {
cut+=(h[i]/ave)*(w[i]/ave);
}
//ave太大不符合要求cut<k,max=ave-1
if (cut<k)
max=ave-1;
//ave小但符合每人都有巧克力的要求cut>k,min=ave+1,记录边长
else{
min=ave+1;
ans=ave;
}
}
System.out.println(ans);
scan.close();
}
}