AcWing 1227:分巧克力 ← 二分法

2024-03-17 06:52

本文主要是介绍AcWing 1227:分巧克力 ← 二分法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【题目来源】
https://www.acwing.com/problem/content/1229/

【题目描述】
儿童节那天有 K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。

切出的巧克力需要满足:
   
○ 形状是正方形,边长是整数
    ○ 大小相同


例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

【输入格式】
第一行包含两个整数 N 和 K。
以下 N 行每行包含两个整数 Hi 和 Wi。
输入保证每位小朋友至少能获得一块 1×1 的巧克力。

【输出格式】
输出切出的正方形巧克力最大可能的边长。​​​​​​​

【数据范围】
1≤N,K≤10^5,
1≤Hi,Wi≤10^5​​​​​​​

【输入样例】
2 10
6 5
5 6

【输出样例】
2

【算法分析】
二分查找,也称为折半查找,是一种高效的查找方法。它基于分治策略,利用数据的
有序性,每次将搜索范围缩小一半,直至找到目标元素或搜索区间为空。二分查找要求必须采用顺序存储结构,且其中的元素按关键字有序排列。

二分查找的经典模板如下:
模板一(从大到小
查找结论 ):当我们将区间 [le, ri] 划分成 [le, mid][mid+1, ri] 时,其更新操作是 ri=mid 或者 le=mid+1,计算 mid 时不需要加 1( 见下文代码中的 int mid=(le+ri)>>1; )。

void BinarySearch(vector<int> v,int target) {int le=0;int ri=v.size();while(le<ri) {int mid=(le+ri)>>1;if(v[mid]<target) le=mid+1;else ri=mid;}
}

模板二(从小到大查找结论 ):当我们将区间 [le, ri] 划分成 [le, mid-1][mid, ri] 时,其更新操作是 ri=mid-1 或者 le=mid,此时为了防止死循环,计算 mid 时需要加 1( 见下文代码中的 int mid=(le+ri+1)>>1; )。

int BinarySearch(vector<int> v,int target) {int le=0;int ri=v.size();while(le<ri) {int mid=(le+ri+1)>>1;if(v[mid]<target) le=mid;else ri=mid-1;}
}

本题题意简述为“给定若干个矩形,若能从中切割出不少于 K 个边长相同的正方形(注意不可拼接),问边长最大能达到多少?”。显然,这是一个从小到大查找结论的问题。故此题适用于二分查找的模板二。

【算法代码】

#include <iostream>
using namespace std;int const N=1e5+5;
int w[N],h[N];
int n,k;bool check(int x) {int cnt=0;for(int i=0; i<n; i++) {cnt+=(w[i]/x)*(h[i]/x);if(cnt>=k) return true;}return false;
}int main() {cin>>n>>k;for(int i=0; i<n; i++) cin>>h[i]>>w[i];int le=1;int ri=1e5;while(le<ri) {int mid=(le+ri+1)>>1;if(check(mid)) le=mid;else ri=mid-1;}cout<<ri;
}/*
in:
2 10
6 5
5 6out:
2
*/





【参考文献】
https://www.acwing.com/blog/content/31/
https://www.acwing.com/solution/content/29446/
https://www.acwing.com/solution/content/140860/
https://blog.csdn.net/meraki/article/details/123739815





 

这篇关于AcWing 1227:分巧克力 ← 二分法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/818157

相关文章

【AcWing】851. 求最短路

spfa算法其实是对贝尔曼福特算法做一个优化。 贝尔曼福特算法会遍历所有边来更新,但是每一次迭代的话我不一定每条边都会更新,SPFA是对这个做优化。 如果说dist[b]在当前这次迭代想变小的话,那么一定是dist[a]变小了,只有a变小了,a的后继(b)才会变小。 用宽搜来做优化,用一个队列,队列里边存的就是所有变小了的结点(队列里存的是待更新的点)。 基本思路就是我更新过谁,我再拿

【AcWing】852. spfa判断负环

#include<iostream>#include<algorithm>#include<cstring>#include<queue>using namespace std;const int N= 1e5+10;int n,m;int h[N],w[N],e[N],ne[N],idx;int dist[N],cnt[N];//cnt存最短路径的边数bool st[N];v

数据结构基础之《(3)—二分法》

一、认识二分法 1、经常见到的类型是在一个有序数组上,开展二分搜索 2、但有序真的是所有问题求解时使用二分的必要条件吗?不 3、只要能正确构建左右两侧的淘汰逻辑,你就可以二分 二、二分法怎么用 1、在一个有序数组中,找某个数是否存在 public static boolean exist(int[] sortedArr, int num) {if (sortedArr == null |

Kotlin 二分法算法游戏--猜价格

本人最新想学习算法,算法是提高程序性能的关键! 程序就是数据结构和算法! 写了一个二分法的游戏,供大家参考: 当然,语言基于kotlin import java.util.*/*** Created by Administrator on 2017/10/18.*/fun main(args: Array<String>) {// println("请输入商品真实价格")//

AcWing 282. 石子合并

必看的视频讲解↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 【E28【模板】区间DP 石子合并——信息学竞赛算法】 合并过程总开销等于红色数字总和,可以理解为花费的总体力! f数组的含义是f【i】【j】是从第i堆石子开始到第j堆石子的花费体力最小值 如何理解三层for呢? 第一层for是控制区间长度len,第二层for是控制区间起点位置i,第三层for是控制区间

二分法变种

package compublic class Test {public static void main(String[] args) {int[] nums = {4,7,7,9,12,13};int index = searchLastSmaller(nums,1);System.out.println(index);}/** 第一个与key相等的元素*/public static int

AcWing 897. 最长公共子序列

动态规划就是多见识应用题就完事儿了,也没有什么好说的。 讲解参考: 【E05 线性DP 最长公共子序列】 #include<iostream>#include<algorithm>#define N 1010using namespace std;char a[N],b[N];int n,m;int f[N][N];int main(){cin >> n >> m >> a

python基础-递归、二分法查找(for\递归)、三级菜单、压栈思想

递归方法二分法查找 通过for循环实现通过递归实现 递归应用–三级菜单压栈 递归方法 # age(1) n = 1 age(2)+2# age(2) n = 2 age(3)+2# age(3) n = 3 age(4)+2# age(4) n = 4 40def age(n):if n == 4:return 40return age(n+1)+2print

AcWing 2. 01背包问题

一定要看的视频讲解:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 【E08【模板】背包DP 01背包——信息学竞赛算法】 i表示放入i个物品,j表示第j个物品,用于访问体积v【j】 #include <iostream>#include <algorithm>using namespace std;const int N = 1010;int n, m;int v[N]

Java 算法的二分法

1.原理 1.1.在升序的集合中对半查找中位的下标,如果中位的下标和要查找的下标相等时,找到目标数,那二分结束。 1.2.如果 集合[中位]大于查找值,说明查找值在中位的左边,那么高位就是此时的中位-1,然后继续二分 1.3.如果集合[中位]小于查找值,说明查找值在中位的右边,那么低位就是此时的中位+1,然后继续二分 1.4.如果低位下标大于高位下标,那就没有找到值 2.实例 /*** @C