先瞎叨叨几句:
不知道该给这种算法起个啥名字,暂且就叫它缩步查找法吧,毕竟用到了缩短步长的思想。这是一个懒惰的产物,因为懒得写二分(其实是因为自己的二分老写错),然后就阴差阳错的想出了这种瞎胡搞的算法。后来在一些比赛中还用到过几次,效果不错,所以就想把这个算法具体给分析一遍,就是因为这算法,我还被实验室的人全黑了一遍,他们都说这是个逗比算法...
进入正题:
查找最基本的有两种,暴力和二分,在这里不谈二分,就说暴力,暴力的思想就是挨个查找看是否符合条件,而暴力是很容易超时的..QAQ。
缩步就是在暴力的基础上的改进,摒弃了暴力挨个查找的冗长步骤,而是通过缩短步长来跳跃式查找,比如说你要从0开始查找,找11112,你可以这样查找:
* 初始位置x为0,初始步长step为10000,然后 x + step = 10000 < 11112 ,没找到;
* 然后继续 x + step = 20000 > 11112,超过了,然后往回退一步,x = 10000 , 这时候把步长step缩短为原来的十分之一,step = 1000;
* 继续x + step = 11000 < 11112 , 继续 x + step = 12000 > 11112,又超过了,继续往回退一步 , x = 11000 , 继续缩步 step = 100;
* 继续x + step = 11100 < 11112 , 继续 x + step = 11200 > 11112 ,同上 x = 11100 , step = 10;
* 继续x + step = 11110 < 11112 , 继续 x + step = 11120 > 11112 ,同上 x = 11110 ,step = 1;
* 最后x + step = 11111 < 11112 , 继续 x + step == 11112 , 就这样找到了。
我一般用这个方法来求解方程组的根、找函数零点一类的,因为这个方法特别容易做一些浮点数的题,并且精度什么的也很好控制,还有一点就是由于这个算法是建立在枚举的思想上面,所以有一点就是不用考虑函数什么的是否递增,所以用这种方法做题还是挺快的。但是一些数组中查找某值的问题还是建议用二分,毕竟这种缩步法只是用来偷懒的,小打小闹而已。
其实这个算法的思想特别简单,原谅了我啰嗦了那么长,大神不要骂我,我只是一个刚接触ACM不久的菜鸟。
下面用代码来实现上面的算法(ps: 具体题目是求函数f(x)的零点 , f(0) < 0):
x = 0; //x的初始查找位置,自己定
step = 1000000; //初始步长,自己定
while(step >= 0.0000001) { //这一步是用来控制精度,自己定
while(f(x + step) < 0.00) //函数f(x), 用 x+step 的话就不用返回到上一步了
x += step; //循环
step /= 10; //缩短步长
}
printf("%.4lf\n", x); //最后得到的x即是所得解
缩步查找法与二分查找法的时间复杂度比较:
如果查找区间长度为N的话,二分是 log2N,这种逗比算法的时间是 5log10N,(因为从1查找到9,平均查找长度是区间长度的一半,所以这个地方就是5) ,算出来查找时间是二分的1.66倍,比二分要稍慢一点,不过比二分好实现一点,ahaha~
还有一些关于用到这个算法的题目,等晚点再往上放。