本文主要是介绍day07 1227分巧克力(整数二分),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1227. 分巧克力
儿童节那天有 K K K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N N N 块巧克力,其中第 i i i 块是 H i × W i H_i×W_i Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N N N 块巧克力中切出 K K K 块巧克力分给小朋友们。
切出的巧克力需要满足:
- 形状是正方形,边长是整数
- 大小相同
例如一块 6 × 5 6×5 6×5 的巧克力可以切出 6 6 6 块 2 × 2 2×2 2×2 的巧克力或者 2 2 2 块 3 × 3 3×3 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N N N和 K K K。
以下 N N N 行每行包含两个整数 H i H_i Hi 和 W i W_i Wi。
输入保证每位小朋友至少能获得一块 1 × 1 1×1 1×1 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
数据范围
1 ≤ N , K ≤ 105 1≤N,K≤105 1≤N,K≤105,
1 ≤ H i , W i ≤ 105 ≤H_i,W_i≤105 ≤Hi,Wi≤105
输入样例:
2 10
6 5
5 6
输出样例:
2
题意: 给定若干个矩形,从中切割出不少于 K K K个边长相同的正方形,问正方形个数不少于 K K K时,边长最大能达到多少
解题思路:
显然是一个二分答案的思路,题目中说了每个小朋友至少能分得一个1×1
大小的正方形,所以边长最小为1
,最大值可以设定一个足够大的数,比如题目中给的数据范围100000
,若当前选择的边长满足要求,则说明还有可能取更长的边长,当然也有可能不能取更长了,答案就是当前这个;若当前这个边长不能满足要求,则说明当前边长不可能是最终答案
满足要求在此题中的意思是至少能够分得K个当前选择边长的正方形
我在此题所选择的性质是当切分的巧克力的边长为mid时,能够切出k个来
,画图如下:
结论:要找的点是红色区间的右边界,即能满足切出的巧克力至少有k个时,切分的巧克力的边长的最大值
如何判断是否满足这个性质?
很容易就可以推出,若当前所取的边长为mid
,对于一个矩形来说,只需要分别用它的长和宽整除这个mid
,然后把结果相乘,就得到这个矩形能够分成多少个边长为mid
的正方形了,把所有的矩形分割的结果相加,就得到总数,可以和K
比较了。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int k = scanner.nextInt();List<Segment> list = new ArrayList<>();//存储输入的所有巧克力的大小for(int i = 0;i < n;i++ ){list.add(new Segment(scanner.nextInt(),scanner.nextInt()));}int l = 1,r = 100000;//题目给出的巧克力的长宽范围,那么切分后的巧克力长宽也在该范围内while(l < r){//结束的时候l = r,故最后输出l和输出r都是可以的//由于是用的l = mid的模板,故这里要加1,即应向上取整,避免死循环//(如l = 3, r = 4,则mid=3,若更新为l=mid,则区间还是3,4,无限死循环了)int mid = l + r + 1>> 1;if(check(list,k,mid)){//判断当切分的巧克力边长为mid时,能否切出k块出来l = mid;//能切出k块,说明边长可以更长,故继续在[mid,r]中尝试切出更长的边长}else{r = mid - 1;//边长为mid时,无法切出k块,则在[l,mid-1]中找合适的边长,mid已知不行了,故是mid-1}}System.out.println(l);}private static boolean check(List<Segment> list, int k, int mid) {int cnt = 0;for(Segment seg : list){//当边长为mid时,一块大巧克力能切出的小巧克力块数为seg.length / mid * (seg.width / mid);//注意第二个括号不能省,因为存在取整,先乘后除与先除后乘得到的结果不一样 ,//如3*2/4 = 1与3*(2/4)=0不同cnt += (seg.length / mid) * (seg.width / mid);}return cnt >= k;}
}class Segment{//代表每块巧克力的长与宽的类public int length;public int width;Segment(int length,int width){this.length = length;this.width = width;}
}
这篇关于day07 1227分巧克力(整数二分)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!