基础算法-二分

本文详细介绍了二分查找算法在整数和浮点数情况下的操作,包括模板题的分析与代码示例,以及一个关于分配馅饼的例题详解,强调了边界定义、区间划分和精度控制的重要性。
摘要由CSDN通过智能技术生成

二分

整数二分

简介:

  1. 先取答案边界l与r
  2. 定义答案mid:mid=l+r>>1或者mid = l+r+1>>1两种方式,根据题目使用其中一种
  3. 编写check()函数
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
	//或者说:当出现不止一个答案时,用来求靠左边的
	int l,r;//给定答案边界
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
	//或者说,当出现不止一个答案时,用来求靠右边的
	int l,r;//给定答案边界
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;

模板题

ITCX7121第一周作业-E(模板)二分
在这里插入图片描述

模板题分析
  1. 先定义答案边界l与r,由于是在数组查找答案,就用数组边界定义l与r,即l = 0,r = n-1 ;
  2. 必须先用第一个模板mid = l+r>>1,求答案的左端
  3. 再用第二个模板mid = l+r+1>>1,求答案的右端
  4. 二分查找不出来目标值x,就返回-1 -1
代码
//二分模板
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int q[N];

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++)
		scanf("%d", &q[i]);
	while (m--) {
		int x;
		scanf("%d", &x);
		int l = 0, r = n - 1;
		while (l < r) {
			int mid = r + l >> 1;
			if (q[mid] >= x)
				r = mid;
			else
				l = mid + 1;
		}
		if (q[l] != x)
			cout << "-1 -1" << endl;
		else {
			cout << l << ' ';
			int l = 0;
			int r = n - 1;
			while (l < r) {
				int mid = r + l + 1 >> 1;
				if (q[mid] <= x)
					l = mid;
				else
					r = mid - 1;
			}
			cout << l << endl;
		}
	}
	return 0;
}

浮点数二分

简介

与整数二分类似

 const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求,一般比输出精度高两位
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;//check函数根据题意写
        else l = mid;
    }
    return l;//返回l,r,mid都行

模板题

ITCX7121第一周作业-F数的三次方根

模板题分析
  1. 根据题目对n的限制,取边界double l = -10000,r = 10000;
  2. 题目结果保留6位小数,这里esp取1e-8
  3. 求数的三次方根,所以check函数为mid*mid*mid>x
代码
#include <iostream>
using namespace std;

int main() {
	double x;
	cin >> x;
	double l = -10000, r = 10000;
	while (r - l > 1e-8) {
		double mid = (r + l) / 2;
		if (mid * mid * mid > x)
			r = mid;
		else
			l = mid;
	}
	printf("%lf", l);
	return 0;
}

二分精选例题

VJ寒假第一周-C pie

例题分析:

  1. 先求出每个馅饼体积,注意高度是1
  2. 遇二分必排序,
  3. 然后取边界l = 0.0,右边界可以是排完序后最大的那块馅饼r = a[n-1],也可以在求体积代码后加上一个sum,算出来所有馅饼的体积和,再用体积和除以总人数 r = sum/f
  4. 再写check函数,判断每个人得到的馅饼体积是否满足要求,用整个馅饼除以每个人可以分得的最大馅饼,一个馅饼一个馅饼的除cnt += int(v[i] / mid);过程中注意取整
  5. 最后判断如果这些馅饼可分得的人数大于总人数了话cnt>=f返回ture,否则返回false

例题代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define Pai acos(-1.0)
using namespace std;
const int N = 10010;
//int r[N];//每块馅饼的半径
double v[N];
int r[N]; //每块馅饼的体积
int n, f; //n:馅饼的数量,f:朋友的数量
int m;

bool check(double mid) {//判断每个人得到的馅饼体积是否满足要求
	int cnt = 0;
	for (int i = 0; i < n; i++) {
		//整个馅饼除以每个人可以分得的最大馅饼,一个一个馅饼的除
		cnt += int(v[i] / mid);//取整
		if (cnt >= f)//可分得的人数大于总人数了话
			return true;
	}
	return false;
}

int main() {
//	cin.tie(0);
//	ios::sync_with_stdio(false);
	scanf("%d", &m);
	while (m--) {

		scanf("%d%d", &n, &f);
		f++;

		for ( int i = 0; i < n; i++) {
			int r ;
			scanf("%d", &r);
			v[i] =   r * r * Pai;
		}

		sort(v, v + n);//二分必排序

		double mid, l = 0.0, r = v[n - 1];
		while (r - l > 1e-6) {
			mid = (r + l) / 2 ;
			if (check(mid))
				l = mid;
			else
				r = mid;
		}
		printf("%.4f\n", l);//
	}
	return 0;
}

例题总结注意

  1. 定于Π时,用反函数acos(-1.0)#defind Pai acos(-1.0),这样Π精度高,尽量别写3.1415926小数
  2. 如果你写了scanf,printf读入输出,尽量加个头文件#include<cstdio>尽管devc++内部自动转换,但是保证做题一次过
  3. 小心题中坑,分馅饼时包括自己,所有别忘了f++;
  4. 注意最后输出占位符用"%.4f\n",不用lf,一直不知道是这里错了
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值