浅谈二分和二分答案
一般来讲我们会在以下情况用到二分:
- 求单调函数的零点
- 求一堆东西的最小值最大是多少
- 很难直接算出答案,但是很好判定答案合不合法
如果想学就继续看吧!
二分查找
二分是一种可以再\(\mathcal{O}(\mathrm{ch}\log m)\)(\(m\)为数据规模,\(\mathrm{ch}\)为判断状态合法性
check()
函数时间复杂度)时间复杂度内求解问题的方法,主要是一个分治,每次将搜索范围减半。
我们以二分查找引入。
有一个有序序列,二分查找的思想如下:
1.定义
L,R,mid
代表答案在[L,R]
内,中点为mid
2.查找mid
所在值,如果mid
大于查找值,搜索范围定为[L,mid]
,如果mid
小于查找值,搜索范围定为[mid,R]
,如果查找到了,则返回L
。
3.将mid
重新设为中点,并调至2
。
- 二分查找的时间复杂度是\(\mathcal{O}(\log n)\)
- 顺序查找的时间复杂度是\(\mathcal{O}(n)\)
现在比较它们两个:
例1:
例2:
代码的话在这:
//二分查找(递归)
int binarySearch(int list[],int left,int right,int number)
{
if(list==NULL) return -1;
int index=0;
int mid=(right+left)/2;
if(left>right)
return -1;
if(number==list[mid])
{
index=mid;
return index;
}
else if(number>list[mid]) binarySearch(list,mid+1,right,number);
else binarySearch(list,left,mid-1,number);
}
//二分查找(循环)
int binarySearch(int list[],int left,int right,int number)
{
if(list==NULL) return -1;
while(left<right)
{
int mid=(right+left)/2;
if (list[mid] == number) return mid;
else if (number > list[mid]) left=mid+1;
else if (number < list[mid]) right=mid-1;
}
return -1;
}
二分答案
二分答案嘛,就是想二分查找一样,只是判断改了,模板:
while(l<r)
{
mid=(l+r)/2;
if (check(mid)) r=mid;
else l=mid+1;
}
check
一般是贪心或DP。
具体应用
比如方程求根啦:
题目描述
有形如:\(ax^3+bx^2+cx^1+dx^0=0\) 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在\(-100\)至\(100\)之间),且根与根之差的绝对值\(≥1\)。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后\(2\)位。
提示:记方程\(f(x)=0\),若存在两个数\(x_1\)和\(x_2\),且\(x_1<x_2\),\(f(x_1)\times f(x_2)<0\),则在\((x_1,x_2)\)之间一定有一个根。
输入格式
一行,\(4\)个实数\(A,B,C,D\)。
输出格式
一行,\(3\)个实根,并精确到小数点后\(2\)位。
输入输出样例
输入
1 -5 -4 20
输出
-2.00 2.00 5.00
这提示明摆着疯狂暗示我们二分啊,按提示二分即可:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define db double
using namespace std;
db a,b,c,d,f1,f2;
int cnt=0;
db check(db x){return a*x*x*x+b*x*x+c*x+d;}
int main()
{
cin>>a>>b>>c>>d;
db l,r,mid;
for(db i=-100;i<=100;++i)
{
f1=check(i);
f2=check(i+1);
if(!f1){printf("%.2lf ",i);cnt++;}
if(f1*f2<0)
{
l=i,r=i+1;
while(r-l>=0.001)
{
mid=(l+r)/2;
if (check(mid)*check(r)>0) r=mid;
else l=mid;
}
printf("%.2lf ",r);
cnt++;
}
if (cnt==3) break;
}
return 0;
}
小学奥数啦:
题目描述
甲、乙两人同时从A地出发要尽快同时赶到B地。出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人。已知甲、乙两人的步行速度一样,且小于车的速度。问:怎样利用小车才能使两人尽快同时到达。
输入格式
仅一行,三个数据分别表示AB两地的距离s,人的步行速度a,车的速度b。
输出格式
两人同时到达B地需要的最短时间,保留6位小数。
输入输出样例
输入
120 5 25
#### 输出
9.600000
这种题想不出来也可以二分啊。
思路如下
然后二分C点啦:
#include<cstdio>
#include<cmath>
int main()
{
double s,s1,s2,v1,v2,t1,t2,p;
double a,b;
scanf("%lf%lf%lf",&s,&v1,&v2);
s1=0;
s2=s;
do
{
p=(s1+s2)/2.0;
a=p/v2;
b=(p-a*v1)/(v1+v2);
t1=a+(s-p)/v1;
t2=a+b+(s-(a+b)*v1)/v2;
if(t1<t2)
s2=p;
else
s1=p;
}
while (fabs(t1-t2)>1e-8);
printf("%.6lf",t1);
return 0;
}
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/12274830.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ