浅谈二分
这一篇blog说说二分查找
其实二分我也是初学,也就是前几天才开始读课本,这几天才开始上手打代码,所以我觉得还是有点难度的,
其实二分粗略的可以理解为一个你npy和你玩的一个游戏,
让你猜1-1000里面的一个数,你每次告诉他一个数,他告诉你比答案大了还是小了,就很简单。
但是如果你是从1开始枚举,而她想的是980,那你放心,你还没猜到,你就重返单身贵族了
所以,我们就要找一种合适的方法来考虑这个问题
心里的目标 173(1--1000) 你的数 关系 500 大了 250 大了 125 小了 187 大了 156 小了 172 小了 180 大了 176 大了 174 大了 173 bingo!
文字有点枯燥对不对?
看一下这个漫画吧 看这
这样下来 我估计你就会觉得二分稍微简单一点点。
这个百度百科对于二分查找过程的一个简单介绍,进行二分的前提是必须要保存一个顺序(升序或降序)
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。它的基本思想是:(这里假设数组元素呈升序排列)将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止;如 果x<a[n/2],则我们只要在数组a的左半部继续搜索x;如果x>a[n/2],则我们只要在数组a的右 半部继续搜索x。
看着是不是有点难受,简单的来说,二分查找就是在过程中,对于你想要的数字的位置 进行一个查找。
最后对于他的位置进行一个报位。
什么??? 还没明白??那你现在至少对于二分有一个简单的了解了吧,那就去做几个题吧。
第一个,
这次的题目啊,真的水到不行,宁看看这题,没有输出入要求,就一个点,那我直接暴力输出不就行了,来看看
我一开始的代码啊
1
2
3
4
5
6
7
8
9
10
11
12
|
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define itn int using namespace std; int main() { cout<< "1.849016" <<endl; return 0; } |
(前面的那一堆头文件是新建就有,不是我特意打上的,逃)
宁看看,满打满算7行就够了,为什么要这么麻烦,还用二分,但是言归正传,我们在水题的时候,当然可以解出方程来,输出。可是如果这个式子再长一点,再难算一点呢?
所以还是要正儿八经的用二分。(话说我们课上刚刚学了二分法解方程)
找零点的时候,只用考虑[f(a)*f(b)<0]&&这个函数是连续不断的就可以了
所以就看一下AC代码吧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define itn int #define E 1e-7 using namespace std; double f( double x) { double y=x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x*x+274*x-121; return y; } int main() { double left=1.5,right=2.4; while (left+E<right) { double mid=(left+right)/2.0; if (f(mid)>0) left=mid; else right=mid; } if (f(left)==0) printf ( "%.6lf\n" ,left); else printf ( "%.6lf\n" ,left); return 0; } |
按要求的六位输出别忘了,
还有就是千万别忘了开double,不然你出不来这个数
别问了 问就是抄的之前的代码
第二个
题目还是比较好理解的,就是从输入的数据里面找两个值,使得这两个数的和为给定的数M,
举例来说,就是
1
2
3
|
4 //输入四个数 2 5 1 4 6 //最终给定的和 |
如果没有解 就输出No!;
那来看看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define itn int using namespace std; int a[100000]; //定义一个一维数组 int main() { int n,m,l,r,mid; //l左指针 r右指针 mid中间数 cin>>n; for ( int i=0;i<n;i++) cin>>a[i]; //输入数据 cin>>m; //和 sort(a,a+n); //按从小到大排序 for ( int i=0;i<n;i++) { l=i; //左 r=n; //右 while (l<=r) { mid = (l+r)/2; if (a[i]+a[mid]==m) { cout<<a[i]<< " " <<a[mid]; //中间取 二分 return 0; } else if (a[mid]+a[i]>m) r=mid-1; //大于就向左取 else l=mid+1; //小于就向右取 } } cout<< "No" ; //没有结果输出No return 0; } |
先把这些数字从大到小排列,方便我们的二分,把中间项定义为mid(最左加最右/2)
然后拿最左与mid来相加与m比较 若是大了就mid向左指一个,反之向右指一个。
其中有一个代码,我一开始写的时候没有加上
1
2
|
l=i; //左 r=n; //右 |
没有明白为什么要这么做
于是第一次交的时候就GG了
后来加上了就AC了。
所以二分一定要记得定义指针啊(这不是指针,但是作用差不多,别杠),不要忘记!!!
第三个是来自于洛谷的题目
#include<iostream> #include<cstdio> long long m,n,a[1000005],temp;//因为我菜,所以就全设成long long; using namespace std; long long check(long long x)//这个check函数是二分的最重要的一环 { long long ans=0; for(int i=1;i<=n;i++) { if(a[i]>x) ans=ans-x+a[i];//ans用来记录能够得到的木材长度 } return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); temp=max(temp,a[i]);//temp用来记录最高的树的高度 } long long l=1,r=temp;//把右边界设成最高的树的高度 while(l<=r)//二分操作 { long long mid=(l+r)>>1,q=check(mid); if(q<m)r=mid-1; else l=mid+1; } printf("%d",r); return 0; }
不解释了自己看吧
其实二分会在很多高难度题目里面出现,所以二分还是一个必不可少的算法,所以尝试去理解,理解完可以去洛谷或者一本通题库里面去a题尝试一下
(我是初学,所以如果有错,请各位大佬指出 谢谢)
原文地址:https://www.cnblogs.com/--840-114/p/12966841.html
- 一个优秀的Android应用从建项目开始
- Ruby OpenSSL 私钥伪造脚本
- 基于 k8s 的 Jenkins 构建集群实践
- Visual C#.Net网络程序开发-Tcp篇(1) 祥细内容:
- 无服务器化的微服务持续交付
- Visual C#.Net网络程序开发-Tcp篇(2) 祥细内容:
- 看你是否够老 – ipman的vxd程序介绍的翻译
- Visual C#.Net网络程序开发-Tcp篇(3) 祥细内容:
- 安全科普:流量劫持能有多大危害?
- OpenSSL心脏出血漏洞全回顾
- Nmap扫描对比工具–libnmap实践
- 如何使用TensorFlow实现神经网络
- 安全科普:详解流量劫持的形成原因
- Office”组合”式漏洞攻击样本分析
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法