蓝桥杯 历届试题 分巧克力 java

Prev 历届试题 分巧克力

题目如下:

image-20201223150713528

这道题是道简单的贪心题,因为要求切出的巧克力要尽可能大

首先我们要知道怎么在一个长方形的巧克力里切出正方形的巧克力,并且能切出的最大面积的正方形的巧克力取决于什么

1.像例子里说一块6x5的巧克力能切出6块2x2的巧克力,这个算法很简单,就是(6 / 2) x (5 / 2) = 3 x 2 = 6。将长方形的长宽分别除以想切出的正方形的边长,得到的值相乘就是答案

2.那一个长方形能切出来最大的正方形的边长是多少?这个值就是min(长,宽)。比如一个1 x 10的长方形,它只能1 x 1的正方形

知道上面两点,再结合下贪心就能写出代码了。代码和注释如下

import java.util.Scanner;

/**
 * @Description: 历届试题 分巧克力
 * @ClassName: Prev37
 * @author: fan.yang
 * @date: 2020/12/23 10:40
 */
public class Prev37 {

    //普通法
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int max = 0;
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        int a[][] = new int[n][2];
        for(int i = 0;i < n;i++){
            a[i][0] = scanner.nextInt();
            a[i][1] = scanner.nextInt();
            //注意一下这个max 这个max最终代表的是所有巧克力能切的最大正方形的边长
            //过程就是 先获取当前巧克力能切的最大正方形边长 min(长,宽)
            //然后在从上面获取到的边长中取最大值 贪心所在
            max = Math.max(Math.min(a[i][0] , a[i][1]) , max);
        }
        //根据max 从大到小看
        for(int i = max;i >= 1;i--){
            int sum = 0;
            for(int j = 0;j < n;j++){
                //根据公式求出 当前巧克力能切出i x i的正方形多少个
                sum += (a[j][0] / i) * (a[j][1] / i);
            }
            //满足要求 直接退出 因为我是从大到小的 第一次满足就是最大的 符合题目的尽可能大
            if(sum >= k){
                System.out.println(i);
                return;
            }
        }
    }

}

把上面的代码往蓝桥一丢,发现最后一个测试数据接近1s了,这说明算法还是有待优化的。

所以最后加了二分法,最后一组数据能在500ms就跑完了

import java.util.Scanner;

/**
 * @Description: 历届试题 分巧克力
 * @ClassName: Prev37
 * @author: fan.yang
 * @date: 2020/12/23 10:40
 */
public class Prev37 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int max = 0;
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        int a[][] = new int[n][2];
        for(int i = 0;i < n;i++){
            a[i][0] = scanner.nextInt();
            a[i][1] = scanner.nextInt();
            max = Math.max(Math.min(a[i][0] , a[i][1]) , max);
        }
        //二分法 注意一下 max要加下1 不然娶不到max的情况
        //比如max = 3时,假设3是答案
        //第一次 left = 0, right = 3 , mid = 1
        //第二次 left = 1, right = 3 , mid = 2
        //第三次 left = 2, right = 3 , mid = 2 
        //这时候循环就结束了 2显然不是最优解 所以max + 1
        int left = 0, right = max + 1;
        while(left < right - 1){
            int mid = (left + right) / 2;
            int sum = 0;
            for(int j = 0;j < n;j++){
                sum += (a[j][0] / mid) * (a[j][1] / mid);
            }
            if(sum >= k){
                left = mid;
            }else{
                right = mid;
            }
        }
        System.out.println(left);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值