二分查找
例题一:
题目来源:HDOJ-2199:Can you solve this equation?
题目大意:给出一个方程8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,再给出一个Y。求出0~100之间的解。
题目分析:最基础的二分查找问题。
AC代码:
#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;
}
double abs(double a) //求绝对值
{
return a>0?a:-a;
}
int main()
{
int t;
double y,left,right,mid;
scanf("%d",&t);
while(t--)
{
scanf("%lf",&y);
if(y<f(0)||y>f(100)) //比較端点函数值
{
puts("No solution!");
continue;
}
else
{
left=0;right=100;
while(right-left>1e-8) //对于double类型的值,应尽量减小误差
{
mid=(left+right)/2;
if(abs(f(mid)-y)<1e-8)
break;
if((f(mid)-y)>1e-8)
right=mid;
else
left=mid;
}
}
printf("%.4lf\n",mid);
}
return 0;
}例题二:
题目来源:HDOJ-2141:Can you find it?
题目大意:给你三个有序数列A, B, C,再给出一个数字 X. 是否能找到三个数字Ai, Bj, Ck, 使得 Ai+Bj+Ck = X.
题目分析:最基础的二分查找问题。避免超时,进行优化,先合并两个数组再进行查找。
AC代码:
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define C 550
int L[C],N[C],M[C];
int LN[C*C];
int find(int LN[],int k,int y) //二分查找
{
int left=0,right=k-1,mid;
while(left<=right)
{
mid=(left+right)/2;
if(LN[mid]==y)
return1;
if(LN[mid]>y)
right=mid-1;
else
left=mid+1;
}
return 0;
}
int main()
{
int l,n,m,s,i,j,k;
int num=1,x,y,q;
while(~scanf("%d%d%d",&l,&n,&m))
{
k=0;
for(i=0;i<l;i++)
scanf("%d",&L[i]);
for(i=0;i<n;i++)
scanf("%d",&N[i]);
for(i=0;i<m;i++)
scanf("%d",&M[i]);
for(i=0;i<l;i++)
for(j=0;j<n;j++)
LN[k++]=L[i]+N[j]; //合并L和N
sort(LN,LN+k); //对LN数组排序
scanf("%d",&s);
printf("Case %d:\n",num++);
while(s--)
{
q=1; // q为标记,1为找不到,0为能找到
scanf("%d",&x);
for(i=0;i<m;i++)
{
y=x-M[i]; //由于L+N+M=x。所以x-M=LN=y
if(find(LN,k,y)) //在LN数组中查找到y
{
puts("YES");
q=0;
break;
}
}
if(q) // 找不到y
puts("NO");
}
}
return 0;
}例题三:
题目大意:有n段长度不等的电缆。要求分成最大长度的k段长度相等的电缆
题目分析:主要的二分查找,寻找最合适的长度。
AC代码:
#include <stdio.h>
double a[100100];
int n,k,i;
bool find(double x) //等长度的电缆段数是否符合要求,并且是否为最长的电缆
{
int sum=0;
for(i=0;i<n;i++)
sum+=(int)(a[i]/x);
return sum>=k;
}
int main()
{
double left,right,mid;
while(scanf("%d%d",&n,&k),n||k)
{
for(i=0;i<n;i++)
scanf("%lf",&a[i]);
left=0;
right=100000;
while(right-left>1e-8) //推断是否符合要求
{
mid=(left+right)/2;
if(find(mid)) //电缆不是最长
left=mid;
else //电缆段数不够
right=mid;
}
right=(int)(right*100)/100.0; //right。mid,left都符合要求。可是right是最大的,更符合要求。
printf("%.2lf\n",right); //并且不能四舍五入。防止电缆不够
}
return 0;
}
浙公网安备 33010602011771号