标签:c语言 simple example hdoj 二分法
在处理计算数学上某函数零点的时候,我们通常是这样做的:
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:
2 100 -4
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; }
还有另一道相似的题:
3 3 3 4 3 3 1 24 5 10 5 1 4 2 3 4 5 6 5 4 2
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的形式将两者都返回。
版权声明:本文为博主原创文章,未经博主允许不得转载。
Num 23 : HDOJ : 2199 Can you solve this equation? + HDOJ : 1969 Pie [ 二分法 ]
标签:c语言 simple example hdoj 二分法
原文地址:http://blog.csdn.net/helloworldonly/article/details/47340177