寒假集训一期(1)——二分查找与二分答案

二分

二分这个词大家应该不会陌生,他是一种思想,经常用来搜索或排序,二分思想就是说要把一串数字对半切开,前提是必须有序,然后比较中间数,不断的缩小范围。

一般的线性查询算法时间复杂度为O(n)

而二分的时间复杂度仅有O(logn)

二分的基本思路与实现

假设有一串数:1 4 7 8 10 13

我们要用二分来搜索10。
第一步:找到中间数:mid=(1+6)/2=3,第三个数为7,
第二步:我们发现10>7,所以要在7的右边查询,这时候左指针移到mid+1处,为4
第三步:更新mid值,mid=(l+r)/2=5
第四步:找到中间数,第五个数为10,程序结束

如果一直没有找到,直到 l >= r,那么意味着这个数串里没有这个数,
这个例子的复杂度只有O(3),如果是线性扫的话就要用O(5)了。

二分答案

二分答案的思想更加巧妙,就是通过不断缩小答案的范围从而找到答案,一般会有if语句判断;

二分样例代码

lef=1,righ=n;
while(lef<=righ){
	mid=(int)((lef+righ)/2);
	if(f>a[mid])
		lef=mid+1;
	else if(f<a[mid])
		righ=mid-1;
	else {
		cout<<mid;
		return 0;
	}
}

二分相关函数

函数名作用
lower_bound (begin,end,n)在begin-end范围内查找第一个大于或等于n的数的位置
upper_bound (begin,end,n)在begin-end范围内查找第一个大于n的数的位置
binary_search(begin,end,n)判断n是否在begin-end范围内

例题:

P. 二分查找

内存限制:64 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较

题目描述

在一个单调递增的序列里查找X。

如果找到x,则返回x在数组中的位置

如果没有找到,则返回-1

输入格式

第1行:1个整数N(1<=N<=2000000), 表示元素的个数

第2行开始的若干行,每行10个空格分开的整数,总共N个整数,即为数组元素。

最后1行,1个整数X,表示要查找的元素

序列的位置从1开始编号。

输出格式

第1行:一个整数,表示x在序列中的位置。如果没有找到,则返回-1

样例

样例输入

5
1 3 5 7 9
7

样例输出

4

分析

这道题是一个非常典型的二分问题,思路如上。

代码

#include<bits/stdc++.h>
using namespace std;
int n,i,f,a[2000005],lef,righ,mid; 
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(i=1;i<=n;i++)
		cin>>a[i];
	cin>>f;
	lef=1;
	righ=n;
	while(lef<=righ){
		mid=(int)((lef+righ)/2);
		if(f>a[mid])
			lef=mid+1;
		else if(f<a[mid])
			righ=mid-1;
		else {
			cout<<mid;
			return 0;
		}
	}
	cout<<-1;
}

E. 二分法求函数的零点

内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较

题目描述

有函数:
在这里插入图片描述

已知 , 且方程 在区间 有且只有一个根,请用二分法求出该根。

输入格式

无。

输出格式

该方程在区间 中的根。要求四舍五入到小数点后4位。

分析

这道题运用二分答案的思想来完成,不断在范围内取mid值,然后移动left或right值,不断缩小范围,从而找到我们要找的答案

代码实现

首先写一个关于这个方程的函数

double f(double x){
	return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x *x+274*x-121;
}

本题给出了范围,可以直接用

double l=1.5,r=2.4,mid;

给出二分答案的核心代码

while(r-l>1e-7){
		mid=(l+r)/2;//取mid值
		if(abs(f(mid))<0.000005){//这道题有精度,要把0写多一点
			printf("%.6lf",mid);
			break;//直接break就行了
		}
		else if(f(mid)>0) l=mid;//随中间值的情况更改范围
		else  r=mid;
	}

完整代码:

#include<bits/stdc++.h>
using namespace std;
double l=1.5,r=2.4,mid;
double f(double x){
	return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x *x+274*x-121;
}
int main(){
	while(r-l>1e-7){
		mid=(l+r)/2;
		if(abs(f(mid))<0.000005){
			printf("%.6lf",mid);
			break;
		}
		else if(f(mid)>0) l=mid;
		else  r=mid;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值