• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
百事可爱
一起努力鸭~~~
博客园    首页    新随笔    联系   管理    订阅  订阅
二分法实例

二分法实例

分巧克力

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

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

输入描述
第一行包含两个整数 N,K (1 <= N, K <=10^5 )。
以下 N 行每行包含两个整数 Hi,Wi (1 <= Hi,Wi <=10^5 )
输入保证每位小朋友至少能获得一块 1x1 的巧克力。

输出描述
输出切出的正方形巧克力最大可能的边长。

输入样例:
2 10
6 5
5 6
输出:2

分析:

用二分查找为判定的前提条件是答案具有单调性,很显然本题巧克力的边长具有单调性,故可以用二分查找解法。

思路:

这道题考察的其实是对图形分割的一种理解,题目要求的是分割成等面积的正方形,那么我们可以知道,一个长为m,宽为n的长方形能分割为宽度为width的正方形的个数:num=(m/width)*(n/width),利用二分查找1到100000中个数大于K中width最大的值输出即可。

package 分巧克力;

import java.util.Scanner;

 //从这 n 块巧克力中切出k块大小相同,形状是正方形巧克力
public class Main {
	
	static int n;
	static int k;//人数
	static int length[] = new int [100005];
	static int width [] = new int [100005];
	
	public static void main(String[] args) {
	  
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		
		for (int i = 0; i < n; i++) {//完成对各个巧克力的长和宽的初始化
		    length[i] = sc.nextInt();
			width[i] = sc.nextInt(); 
		}
		
		//二分查找
		int low = 1, high = 100000;
		int mid = (low + high) /2;
		
		while(low <=high) {
			mid = (low + high) /2;
			if(judge(mid)) {
				low = mid+1;//如果mid是符合条件的宽度,则可以令下限加1,寻找符合条件的更大的边长
			}
			else high = mid-1 ;        
		}
		System.out.println(mid);
	}
	
	public  static boolean judge(int w) {//判断函数,判断宽度为width时切分的个数是否大于人数
		int cnt = 0;
		for (int i = 0; i < n; i++) {
			cnt += (length[i] / w) * (width[i] / w);
		}
		if(cnt >= k)
			return true;
		else 
			return false;
	}
 
// int[3][4]; 3个一维数组,每一个一维数组当中有4个元素  a[二维数组中一维数组下标][一维数组中的下标]
}

分析题目:

这K块巧克力都是正方形而且大小都是一样的, 希望找到边长尽可能大的巧克力使得切出来的个数满足K个小朋友的需求。题目已知最大的矩形边长为100000,最小边长为1我们的目标是在这个范围内找到一个边长最大为t的正方形,使得切出来的个数是大于或等于K,分析到这里应该可以想到二分查找了吧。二分查找解决的题目一般是已知一个范围,求解的问题是一般是从这个范围中找出满足题目要求的最佳值

二分查找一般都是可以使用模板解决的,首先在循环中求解出左右边界[l, r]的中间范围,通过一个check函数传递这个中间范围结合题目的要求判断当前的mid是否满足题目的条件,如果满足那么就更新左边界或者是右边界,在check函数中满足的条件下可以使用一个变量r来记录满足题目要求的中间值(使用变量记录的目的是为了避免最后左右边界上的处理导致的错误),最后根据题目的要求输出或者返回r 变量值即可。对于这道题目来说我们需要在最小范围1与最大范围100000中找到一个最大的边长mid,使用check函数判断当前的边长mid是否满足切出来的数目大于等于k的条件

M 次方根

打算设计一个程序用于求解 M 次跟下N的值。
但是由于要考虑精度范围,答案必须要保留 7 位小数,连三次根号下 27 都要掰手指的小 A 又怎么会设计呢。请你帮小 A 设计一个程序用于求解 M 次根号 N。
数据范围:
1<= N <= 1e5
1<= M <= 100
且 M<N

输入描述: 第一行输入整数 N 和 M,数据间用空格隔开。

输出描述: 输出一个整数,并保留 7 位小数。

输入样例:

27 3

输出样例:

3.000000

分析题目:

前面讲的都是整数二分,其实二分法还是可以用于实数;要找到一个具有单调性的数列,去二分。这个题的关键是我们要去二分什么,这里可以二分的是 a^M=N 中的 a,N所以我们要先想办法设计出用于处理实数二分的代码。

以下是一个模板:

实数域二分,设置eps法:

//令eps 为小于题目精度一个数即可。
//比如题目说保留4位小数,0.0001 这种的。那么eps 就可以设置为五位小数的任意一个数 0.00001 到 0.00009 都可以。一般为了保证精度,我们也会选取精度 /100 的那个小数,即设置  eps= 0.0001/100 = 1e-6。(表示1乘以10的负6次方)

while (l + eps < r) {
  double mid = (l + r) / 2;
  if (pd(mid)) 
      r = mid; 
  else 
      l = mid;
}

关于判定条件,我们应该设计一个代码用于比较 a^M 和 N 的大小关系。

pd 成功的情况,一定是 pd 的 mid 符合条件,且小于 mid 的一定符合条件。因此我们要在大于 mid 中继续查找,找到更大的 mid。

double pd(double a,int m)// a^m=n 判断a是否符合
{
    double c=1;
    while(m>0)//此处实现a的m次方
    {
        c=c*a;
        m--;
    }//可以利用2^3=8 a=2 m=3 那最后c=8 那n=7
    if(c>=n)
        return true;
    else
        return false;
}

代码实现

package 二分法样例;
/*求解 M 次根号 N*/
import java.util.Scanner;

public class FangGen {

	static double n, l, r, mid; 
	static double eps = 1e-8;//为了保证精度

	static boolean pd(double a, int m) {
		double c = 1;
		while (m > 0) {
			c = c * a;
			m--;
		}
		if (c >= n)

			return true;

		else
			return false;
	}

	
	public static void main(String[] args) {
		int m;
		Scanner in = new Scanner(System.in);
		n = in.nextDouble();
		m = in.nextInt();
		// 设置二分边界(指的是a^m=n 中的a的取值范围),二分的是 a^M=N 中的 a
		l = 0;
		r = n;
		// 实数二分
		while (l + eps < r) {
			double mid = (l + r) / 2;
			if (pd(mid, m))//pd 成功的情况,一定是 pd 的 mid 符合条件,且小于 mid 的一定符合条件。因此我们要在大于 mid 中继续查找,找到更大的 mid。
				r = mid;
			else
				l = mid;
		}

		System.out.println(String.format("%.7f", l));
	}
}
posted on 2022-03-20 11:35  精致猪猪侠  阅读(472)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3