在处理计算数学上某函数零点的时候,我们通常是这样做的:
1. 先判断这个零点在某个单调区间 [ a,b ]上( 假设为递增区间 );
2. 之后判断 f(x) 在 (a+b)/2 [ a,b中点处 ]是否为零;
3. 若中点处大于零,b=( a+b )/2 ;否则,同理,a=( a+b )/2 ;
4. 重复2.3.过程,直到找到零点,或满足精度;
如图( 图片来自百度 ):
C语言基于这个原理,也有了自己的二分法;
二分法:
在某一特定的序列之中[
通常是已经排过序的数列 ]寻找某一特殊值[ 满足条件的最大最小值 ]的方法;
与通常的寻找方式不同,二分法采用的是折半查找的方式,比一般的需要游历所有数据的方法更省事;
但是需要注意的是: 二分法只能处理排过序的数据,未排序的不能够直接使用二分法!!
实现代码:
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; }
需要定义至少四个变量: left , right , mid; path;
left: 区间的左边界;
right: 区间的右边界;
mid: 区间的中点;
path: 可否取得的极值;
代码分析:
当 left<right 时,执行程序;
通过mid的变化,不断接近 path,直到 right<left ;
left=mid+1; right=mid - 1 ;是为了保证程序在left=right=mid的时候,不会造成死循环;
例:HDOJ2199:
Can you solve this equation?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13146 Accepted Submission(s): 5886
Problem Description
Now,given the equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,can you find its solution between 0 and 100;
Now please try your lucky.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has a real number Y (fabs(Y) <= 1e10);
Output
For each test case, you should just output one real number(accurate up to 4 decimal places),which is the solution of the equation,or “No solution!”,if there is no solution for the equation between 0 and 100.
Sample Input
2 100 -4
Sample Output
1.6152 No solution!
纯数学问题,直接引用上一段代码即可:
AC代码:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> double fab(double x) { return x<=0?-x:x; } double fun(double x) { return 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6.0; } int main() { int t; scanf("%d",&t); while(t--) { double y,mid,left,right;; scanf("%lf",&y); if(y<fun(0)||y>807020306) printf("No solution!\n"); else { left=0.0;right=100.0; while(fab(right-left)>=1e-10) { mid=0; mid=(left+right)/2; if(fab(fun(mid)-y)<=1e-10) break; else if(fun(mid)-y>0) right=mid; else left=mid; } printf("%.4lf\n",mid); } } return 0; }
还有另一道相似的题:
Pie
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6644 Accepted Submission(s): 2517
Problem Description
My birthday is coming up and traditionally I‘m serving pie. Not just one pie, no, I have a number N of them, of various tastes and of various sizes. F of my friends are coming to my party and each of them gets a piece of pie. This
should be one piece of one pie, not several small pieces since that looks messy. This piece can be one whole pie though.
My friends are very annoying and if one of them gets a bigger piece than the others, they start complaining. Therefore all of them should get equally sized (but not necessarily equally shaped) pieces, even if this leads to some pie getting spoiled (which is
better than spoiling the party). Of course, I want a piece of pie for myself too, and that piece should also be of the same size.
What is the largest possible piece size all of us can get? All the pies are cylindrical in shape and they all have the same height 1, but the radii of the pies can be different.
Input
One line with a positive integer: the number of test cases. Then for each test case:
---One line with two integers N and F with 1 <= N, F <= 10 000: the number of pies and the number of friends.
---One line with N integers ri with 1 <= ri <= 10 000: the radii of the pies.
Output
For each test case, output one line with the largest possible volume V such that me and my friends can all get a pie piece of size V. The answer should be given as a floating point number with an absolute error of at most 10^(-3).
Sample Input
3 3 3 4 3 3 1 24 5 10 5 1 4 2 3 4 5 6 5 4 2
Sample Output
25.1327 3.1416 50.2655
题目分析:
与上一道题基本相同,但是要判断的是蛋糕要分配的人数;( 一般二分的关键都在于终止条件的判断 )
还有一点,这道题比较坑的就是,再分配蛋糕的时候,也要考虑到自己;
所以输入人数后要people++;
AC代码:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #define pi acos(-1.0) double cake[10010]; double maxfun(int a,int b) { return a>b?a:b; } int main() { int c; scanf("%d",&c); while(c--) { int num,people; double r,max,sum,mid,left,right; sum=0.0;max=0.0; scanf("%d%d",&num,&people); people++; for(int i=1; i<=num; i++) { scanf("%lf",&r); cake[i]=pi*r*r; sum+=cake[i]; max=maxfun(max,cake[i]); } left=max/people;right=sum/people; while(right-left>=0.000001) { int peoplenum=0; mid=(right+left)/2; for(int p=1; p<=num; p++) peoplenum+=(int)(cake[p]/mid); if(peoplenum<people) right=mid; else left=mid; } printf("%.4lf\n",left); } return 0; }
在C++的STL中也提供了关于二分查找的一些函数,这里仅作介绍:
STL包含四种不同的二分查找算法:
binary_search
lower_bound
upper_bound
equal_range
只有在数据排序的情况下才可以做处理;
binary_search:在已排序的 [ left,right ) 中寻找元素path. 如果 [ left, right) 内有等于path的元素,它会返回true,否则返回false,它不返回查找位置。
lower_bound:它在已排序的 [ left,right )
中寻找元素path. 如果 [ left,right )
具有等于path的元素,lower_bound返回一个iterator指向其中第一个元素。如果没有这样的元素存在,它便返回假设这样的元素存在的话,会出现的位置。即指向第一个不小于path的元素。如果path大于
[ left,right ) 的任何一个元素,则返回last.
upper_bound:它在已排序的
[ left,right ) 中寻找path,返回可安插path的最后一个合适的位置。如果path存在,lower_bound 返回的是指向该元素的iterator。相较之下upper_bound并不这么做,它返回path可被安插的最后一个合适位置。如果path存在,那么它返回的iterator将指向path的下一个位置,而非path自身。
equal_range:返回值本质上结合了lower_bound和upper_bound两者的返回值。其返回值是一对iterator i 和 j , 其中i是path可安插的第一个位置,j则是path可安插的最后一个位置。可以推演出:[i,j)中的每个元素都等价于path,而且[i, j)是
[ left,right ) 之中符合上述性质的一个最大子区间。 算法lower_bound返回该range的第一个iterator, 算法upper_bound返回该range的past-the-end iterator,算法equal_range则是以pair的形式将两者都返回。
版权声明:本文为博主原创文章,未经博主允许不得转载。