zoukankan      html  css  js  c++  java
  • 倪文迪陪你学蓝桥杯2021寒假每日一题:1.11日(2017省赛A第9题)

    2021年寒假每日一题,2017~2019年的省赛真题。
    本文内容由倪文迪(华东理工大学计算机系软件192班)和罗勇军老师提供。

    后面的每日一题,每题发一个新博文,请大家看博客目录https://blog.csdn.net/weixin_43914593
    @

    2017省赛A类第9题,题目链接:
    分巧克力 http://oj.ecustacm.cn/problem.php?id=1323

    1、题目描述


    有N个长方形,第i个长方形的边长是Hi, Wi
    把长方形分成相同的正方形,不少于K个。
    问正方形最大的边长是多少?
    数据规模:1 <= N, K <= 100000,1 <= Hi, Wi <= 100000


    2、题解

    2.1 暴力

      先试试暴力。暴力的思路很简单:把边长从1开始到最大边长D,每个值都试一遍,一直试到刚好够分的最大边长为止。
      编码:边长初始值d=1,然后d=2,3,4,...一个个试。
      暴力法的复杂度:n个长方形,长方形的最大边长D,复杂度是(O(n imes D)),而n和D的最大值是10万,会超时。
      暴力代码:

    #include<bits/stdc++.h>
    using namespace std;
    int h[100010],w[100010];
    int n,k;
    bool check(int d){ //检查够不够分
        int num=0;
        for(int i=0;i<n;i++)
            num += (h[i]/d)*(w[i]/d);
        if(num>=k) return true;    //够分
        else       return false;   //不够分
    }
    
    int main(){
        cin >>n>>k;
        for(int i=0;i<n;i++)  cin>>h[i]>>w[i];
        int d=1;         //正方形边长
        while(1){
            if(check(d))
               d++;    //边长从1开始,一个个地暴力试试
            else
               break;
        }
        cout << d-1;
        return 0;
    }
    

    2.2 二分法

      既然一个个试边长d太慢了,那就祭出二分大法,对边长d的取值范围二分,复杂度一下子从O(D)优化到了O(logD)。
      所谓二分法,就是每一次把搜索范围减少一半。
      第一次:开始时d的范围是1~D,试试中间值D/2,如果这个值大了,就把范围缩小为0~D/2(如果这个值小了,就把范围缩小为D/2~D);
      第二次,取新的中间值D/4,再试......
      直到找到合适的值为止。
      二分法是一个基本的优化方法。二分法的学习,参考博文:
      https://blog.csdn.net/weixin_43914593/article/details/103250854
      这篇文章详细介绍了二分法的原理、代码、典型应用。

    3、C++代码

      整数的二分法的编码虽然简单,但是很容易出错。左右边界L、R和中间值mid的迭代,由于整数的取整问题,极易出错。
      下面的整数二分代码,给出了两种写法,请仔细体会。
      OJ运行时间77ms

    #include<bits/stdc++.h>
    using namespace std;
    int n,k;
    int h[100010],w[100010];
    bool check(int d){
        int num=0;
        for(int i=0;i<n;i++)
            num += (h[i]/d)*(w[i]/d);
        if(num>=k) return true;    //够分
        else       return false;   //不够分
    }
    int main(){
        cin >>n>>k;
        for(int i=0;i<n;i++)   cin>>h[i]>>w[i];
    
        int L=1, R=100010;
    //整数二分法的L、R、mid如果处理不当,极容易死循环。
    //请仔细领会下面两种写法
    
    //  第一种写法:
        while(L<R) {
            int mid=(L+R+1)>>1;   //除2,向右取整
            if(check(mid))     
            	L=mid;  //新的搜索区间是右半部分,所以R不变,调整L=mid;
            else               
            	R=mid-1; //新的搜索区间是左半部分,所以L不变,调整R=mid–1。
        }
        cout << L;
    
    //  第二种写法:
    /*  while(L<R) {
            int mid=(L+R)>>1;  //除2,向左取整
            if(check(mid))    
            	L=mid+1;//新的搜索区间是右半部分,R不变,更新L=mid+1。
            else
                R=mid;  //新的搜索区间是左半部分,L不变,更新R=mid
        }
        cout << L-1;
    */
        return 0;
    }
    

    4、Java代码

      OJ上运行时间2.5s

    //newoj User:20185012;
    import java.util.Scanner;
     
    public class Main {
        private static int maxn = 100000;
        public static void main(String[] args) {
            int n,k;
            int[] h = new int[maxn];
            int[] w = new int[maxn];
            Scanner scanner = new Scanner(System.in);
            n = scanner.nextInt();
            k = scanner.nextInt();
            for (int i = 0; i < n; i++) {
                h[i] = scanner.nextInt();
                w[i] = scanner.nextInt();
            }
            int ans = 0;
            int right = maxn + 1;
            int left = 1;
            while (left<=right){
                int mid = (left + right) >> 1;
                int cnt = 0;
                for (int i = 0; i < n; i++) {
                    cnt += (h[i] / mid) * (w[i] / mid);
                }
                if (cnt >= k){
                    left = mid + 1;
                    ans = mid; // 及时记录结果!!!!!!
                }else
                    right = mid - 1;
            }
            System.out.println(ans);
        }
    }
    

    5、Python代码

      OJ运行时间1.5s。

    def check(d):
        global w,h
        res = 0
        for i in range(len(w)):
            res += (w[i]//d) * (h[i]//d)
        if res >= k:  return True
        return False
    
    n,k = map(int,input().split())
    w = []
    h = []
    for i in range(n):
        a,b = map(int,input().split())
        w.append(a)
        h.append(b)
    
    L ,R = 1, 10000
    while L < R:
        mid = (L+R)//2
        if check(mid):  L = mid +1
        else :          R = mid
    print(L-1)
    
  • 相关阅读:
    python随机生成
    socket、tcp、http
    TCP三次握手和http过程
    iOS多线程的初步研究(十)-- dispatch同步
    dispatch队列
    IOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
    UIWebView 自定义网页中的alert和confirm提示框风格
    dispatch_semaphore
    app内购提示,您已购买此商品,但未下载
    单例的写法
  • 原文地址:https://www.cnblogs.com/luoyj/p/14271428.html
Copyright © 2011-2022 走看看