二分------猜数字:
假设需猜的数字x取值范围是[1 , n] ,算法复杂度为o(log2(n))。
代码:
hdu--2199
int Q(int left, int right, int path){
int mid;
while(left <= right){
mid = (left + right) / 2;
if( mid < path ) left = mid + 1;
else right = mid - 1;
}return right;
}
适用范围:当数据量很大适宜采用该方法。
要求:采用二分法查找时,数据需是排好序的。(数据无序时,不能用!),有时通过将数据存储,然后排序后再采用二分,例如hdu--2141;
采用二分时,要注意数据的精确度,与循环的时间;数据精度按题意需考虑left,mid,right三者之间的关系。循环时间有时通过Left与right的大小关系决定循环时间,有时通关大致判断折半次数直接用一个具体的数表示循环次数。
例题:
hdu----1064
#include<stdio.h>
#define M 10010
double a[M];
int n;
int f(double x)
{
int i,s;
s=0;
for(i=0;i<n;i++)
s+=(int)(a[i]/x);
return s;//可以截的段数
}
int main()
{
int i,k;
double r,l,mid;
while(scanf("%d%d",&n,&k)!=EOF){
for(i=0;i<n;i++)
scanf("%lf",&a[i]);
l=0;r=100000;
while(r-l>1e-8)
{
mid=(l+r)/2;
if(f(mid)<k)
r=mid;
else l=mid;
}
r=(int)(r*100)/100.0;//选取返回r,而不是mid;r>mid>l;应为此时三个数大小非常接近,而在后面需要对数据处理,只有 right数据最精确
/*样例4 100 0.1 0.2 0.3 0.4;*/
printf("%.2f\n",r);
}
return 0;
}
hdu--2199
#include<stdio.h>
#include<math.h>
double f(double x){
return 8*pow(x,4)+7*pow(x,3)+2*pow(x,2)+3*x+6;
}
int main()
{
int t;
double y,r,l,mid,k;
scanf("%d",&t);
while(t--){
scanf("%lf",&y);
l=0;r=100;
if(f(l)>y||y>f(r)){
printf("No solution!\n");
continue;
}
else {
while(r-l>1e-8){/*当这里变成while(1),跳出循环条件变成if(fabs( f(mid)- y)<1e-8)break;
就超时了,因为这里求的是近似解*/
mid=(l+r)/2;
k=f(mid);
if(fabs(k-y)<1e-8)break;
if(k>y)r=mid;
else l=mid;
}
printf("%.4f\n",mid);
}
}
return 0;
}
2.二分有关函数:(STL系列)
lower_bound(begin,end,index)
找到大于等于某值的第一次出现
upper_bound(begin,end,index)
找到大于某值的第一次出现
例题:hdu--2141
/*法一*/
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define M 41000
using namespace std;
int a[M];
int main()
{
int n,p,m,k,i,t,end;
scanf("%d",&n);
while(n--)
{
memset(a,0,sizeof(a));
scanf("%d",&p);
scanf("%d",&m);
a[1]=m;end=1;
for(i=2;i<=p;i++)
{
scanf("%d",&t);
if(t>a[end])a[++end]=t;
else
{
k=lower_bound(a+1,a+end,t)-a;
a[k]=t;
}
}
printf("%d\n",end);
}
return 0;
}
/*法二*/
#include<stdio.h>
#include<string.h>
#define M 41000
int a[M];
int main()
{
int n,p,m,k,i,t,end,l,r,mid;
scanf("%d",&n);
while(n--)
{
memset(a,0,sizeof(a));
scanf("%d",&p);
scanf("%d",&m);
a[1]=m;end=1;
for(i=2;i<=p;i++)
{
scanf("%d",&t);
if(t>a[end])a[++end]=t;
else
{
l=1;
r=end;
mid=(r+l)/2;
while(l<r)
{
if(a[mid]<t)
l=mid+1;
else
r=mid;
mid=(r+l)/2;
}
a[mid]=t;
}//二分法lower_bound的原理
}
printf("%d\n",end);
}
return 0;
}
可以看看stl源码学习之lower_bound有助于更加了解二分的作用。