真题99—巧克力切割(二分查找)
文章目录
1. 问题描述
儿童节时,小明家迎来了 K 位小朋友。为了招待小朋友,小明拿出 N 块巧克力。每块巧克力是由 H**i×W**i 个方格组成的长方形。为确保公平,小明需从这 N 块巧克力中切出 K 块正方形巧克力,且这些正方形巧克力需满足:
- 形状为正方形,边长为整数。
- 所有切出的正方形巧克力大小相同。
例如,一块 6×5 的巧克力,能够切出 6 块 2×2 的巧克力,或者 2 块 3×3 的巧克力。目标是帮助小明计算出能切出的正方形巧克力的最大边长。
2. 输入输出规范
2.1 输入描述
- 第一行包含两个整数 N 和 K,其中 1≤N,K≤105。
- 接下来的 N 行,每行包含两个整数 H**i 和 W**i,表示第 i 块巧克力的尺寸,且 1≤H**i,W**i≤105。
- 输入保证每位小朋友至少能获得一块 1×1 的巧克力。
2.2 输出描述
输出切出的正方形巧克力的最大可能边长。
2.3 输入输出样例
示例
输入
2 10
6 5
5 6
输出
2
3. 代码实现
3.1 解题 代码
public class _99 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int k = scan.nextInt();
int maxSide = 0;
int[] widths = new int[n];
int[] heights = new int[n];
for (int i = 0; i < n; i++) {
widths[i] = scan.nextInt();
heights[i] = scan.nextInt();
//计算巧克力最短边,可切割最长变长
if (maxSide == 0) {
maxSide = Math.max(widths[i], heights[i]);
} else {
maxSide = Math.max(maxSide, Math.min(widths[i], heights[i]));
}
}
// 二分查找的左边界,最小边长为 1
int left = 1;
// 二分查找的右边界,最大边长为 maxSide
int right = maxSide;
// 开始二分查找,当左边界小于等于右边界时继续循环
while (left <= right) {
// 计算中间值,作为当前尝试的边长
int mid = left + (right - left) / 2;
// 用于统计当前边长下能切出的正方形巧克力总块数
int count = 0;
// 遍历每块巧克力,计算能切出的边长为 mid 的正方形数量
for (int i = 0; i < n; i++) {
// 计算当前巧克力能切出的边长为 mid 的正方形数量并累加到 count 中
count += (widths[i] / mid) * (heights[i] / mid);
}
// 如果切出的总块数大于等于 k,说明当前边长可行,尝试更大的边长
if (count >= k) {
left = mid + 1;
} else {
// 否则,说明当前边长太大,尝试更小的边长
right = mid - 1;
}
}
System.out.println(right);
}
}
3.2 代码逻辑解析
- 数据读取:程序首先使用
Scanner
从标准输入读取巧克力的数量 N、小朋友的数量 K,以及每块巧克力的宽度 W**i 和高度 H**i,并将这些数据存储在数组widths
和heights
中。 - 确定二分查找范围:通过遍历输入的巧克力尺寸,找到所有巧克力中可能的最大边长
maxSide
。将二分查找的左边界left
初始化为 1,右边界right
初始化为maxSide
。 - 二分查找过程:在
left
小于等于right
的条件下,计算中间值mid
。遍历每块巧克力,计算以mid
为边长能切出的正方形巧克力数量,并累加到count
中。如果count
大于或等于 K,说明当前边长mid
可行,将left
调整为mid + 1
,尝试更大的边长;否则,将right
调整为mid - 1
,尝试更小的边长。 - 结果输出:循环结束后,
right
即为满足条件的最大边长,将其输出。
4. 二分法使用及适用场景
4.1 二分法原理
二分法,也称为折半查找法,是一种在有序数组或具有有序性质的数据结构中高效查找目标值的算法。其基本思想是将数据集合分成两部分,通过比较目标值与中间元素的大小,决定继续在左半部分还是右半部分进行查找,每次查找都将数据集合的规模减半,从而显著提高查找效率。
4.2 适用场景
- 有序数组查找:最常见的应用场景是在有序数组中查找特定元素。例如,在一个升序排列的整数数组中查找某个目标整数,二分法可以将查找时间复杂度从线性时间 O(n) 降低到对数时间 O(logn)。
- 求解最值问题:当问题可以转化为在一个单调递增或递减的函数中寻找满足特定条件的最值时,二分法也适用。在巧克力切割问题中,随着正方形边长的增加,能切出的巧克力块数会单调递减。通过二分法,我们可以在可能的边长范围内快速找到满足小朋友数量要求的最大边长。
- 查找满足特定条件的边界值:二分法可用于查找满足某种条件的边界值。例如,在一个有序数组中查找第一个大于或等于某个值的元素,或者查找最后一个小于或等于某个值的元素。s
围内快速找到满足小朋友数量要求的最大边长。
3. 查找满足特定条件的边界值:二分法可用于查找满足某种条件的边界值。例如,在一个有序数组中查找第一个大于或等于某个值的元素,或者查找最后一个小于或等于某个值的元素。s
二分法在解决具有单调性和可二分性的问题时表现出色,能够显著提高算法的时间效率,降低时间复杂度。