二分法:
求具有单调函数中逼近求解某点的值,是求f(x)==y 时x的值是什么,通常来说y为0,但也不言定。特定:查找中我们由二分查找,在有序数组中查找特定元素的算法 排序中是二分排序,也就是快排,归并排序
二分查找适合有序的数组进行查找:
#include<iostream>
#define N 10
using namespace std;
int main()
{
int a[N],front,end,mid,x,j;
int a[N]={.....};//假设已排好序
cin>>x;//s输入要查找的数x;
front=0; end=N-1;//各指向首尾
mid=(front+end)/2;
while(front<end&&a[mid]!=x)
{
if(a[mid]<x) front=mid+1;
if(a[mid]>x) end=mid-1;
mid=(front+end)/2;
}
if(a[mid]!=x)//没找到
else //找到了
}
时间复杂度
1.最坏情况查找最后一个元素(或者第一个元素)Master定理T(n)=T(n/2)+O(1)所以T(n)=O(log2n)
2.最好情况查找中间元素O(1)查找的元素即为中间元素(奇数长度数列的正中间,偶数长度数列的中间靠左的元素)
递归(其实差不多):
int BinSearch(int a[],int low,int high,int k )
{
int mid;
if(low<=high)
{
mid=(low+high)/2;
if(a[mid]==k)
return mid;
if(a[mid]>k)
return BinSearch(a,low,mid-1,k);
else
return BinSearch(a,mid+1,high,k);
}
return -1;
}
三分法:
我们都知道 二分查找 适用于单调函数中逼近求解某点的值。
如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。
思路:通过不断缩小 [L,R] 的范围,无限逼近白点。
做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。
当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。
1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。
反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。
所以,此时可以将 R = mmid 来缩小范围。(通过分析得到的)
2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。
反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。
同理,此时可以将 L = mid 来缩小范围。(通过分析得到的)
写法:
(先增后减型)
nt SanFen(int l,int r) //找凸点 差不多同上图
{
while(l < r-1)
{
int mid = (l+r)/2;
int mmid = (mid+r)/2;
if( f(mid) > f(mmid) )
//右端移动到nmid处
r = mmid;
//左端移动到mid处
else
l = mid;
}
return f(l) > f(r) ? l : r;
}
(先减后增 易知与上面相反)
int SanFen(int l,int r) //找凸点
{
while(l < r-1)
{
int mid = (l+r)/2;
int mmid = (mid+r)/2;
if( f(mid) > f(mmid) )
l = mid;
else
r = mmid;
}
return f(l) > f(r) ? l : r;
}
为什么不能用二分法 因为如果想求一个抛物线的极大值的话,二分是不行的,因为二分其实就是缩短[L,R]区间,以mid为参考不断缩短区间距离。
如果用二分法,抛物线求极值的话,单纯二分没法确定极值点所在区间,
所以可以用三分
int mid = (l+r)/2;
int mmid = (mid+r)/2;
这样子根据图片就可以确定出三种情况 但是如果f(mid)==f(nmid)就令l=mid或r=nmid就行了
hdu2438
题意:给出一个90度转弯,对应宽窄x y如图所示,车对应宽窄l d如图所示,问你这辆车能否顺利通过
(这题知道三分法就比较好解决了 当时画了下图 求了方程只知道求这个方程极大值但不知道用程序怎么求。。)
大佬的图 直线比较好求,最终就是车翻转时在任意一点那个P点的横坐标的绝对值都不能大于Y,因为大于Y就撞上了,而且可以看出来P点跟蓝色直线的焦点横坐标绝对值先增大后减小,只要找极大值就行了,极大值小于等于Y,就能通过.
#include<iostream>
#include<cmath>
#include<stdio.h>
const double eps=1e-9;
double X,Y,L,D;
double PI=acos(-1.0);
double distance(double angle)
{
return(-X+L*sin(angle)+D/cos(angle))/tan(angle);
}
int main()
{
while(scanf("%lf %lf %lf %lf",&X,&Y,&L,&D)!=EOF)
{
if(X<D||Y<D)
{
printf("no\n");
continue;
}
double low=0,up=PI/2,mid,mmid;
double dis1,dis2;
while(true)
{
mid = (low + up) / 2;
mmid = (mid + up) / 2;
dis1 = distance(mid);
dis2 = distance(mmid);
if(dis1 > dis2) up = mmid;
else low = mid;
if(up - low < eps) break;
}
if(dis1)<=Y;
printf("yes\n");
else
printf("no\n");
}
}
From:
https://blog.csdn.net/huzujun/article/details/81187455?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/u013761036/article/details/24588987