算法描述》关于二分的两三事

  关于二分

   二分,是一种流氓算法,这种方法适用于直接算(猜、蒙、试)答案,然后直接得出最优解,

  这一方法,对于可以轻易证明答案是否可行(o(n)、o(1))的题目有奇效,

  (在NOIP2015考试的时候出了这么一道题,放倒一推蒟蒻(包括我))

  二分的使用条件

  1.如上文所说,对于轻易证明答案是否可行的题目有奇效,来一道解决一道,对于子问题有这一性质的,也可以同样用这种方法解决,奇效。(以下有相关内容)

  2.对于所查询区间值为递增或递减的问题来说,这也是一种极其可行的方法,

  关于写法以及STL若干事

  每一位神犇几乎都有自己有个性的二分写法,因为这个东西可以有所差异的地方实在太多,但究其本身,还都是同一种道理。

  1.关于<algorithm>中,STL的写法

  在c++的库函数里,有两个二分函数,分别叫upper_bound和lower_bound。

  

  upper_bound

  这一库函数的定义是:在当前传来的非降序列两个地址中间,return第一个大于当前传来的值的地址

  使用格式为:upper_bound(a+1,a+n+1,num);

  其中a数组为我们所要查询的非降数组,而1、n+1分别为我们要查找的区间地址(也即数组变量名+查询的开始 / 结束位置),num为我们所要查询的值。

  具体库函数代码如下

 1 int upper_bound(int *array, int size, int key)
 2 {
 3     int first = 0, len = size-1;
 4     int half, middle;
 5 
 6     while(len > 0){
 7         half = len >> 1;
 8         middle = first + half;
 9         if(array[middle] > key)     //中位数大于key,在包含last的左半边序列中查找。
10             len = half;
11         else{
12             first = middle + 1;    //中位数小于等于key,在右半边序列中查找。
13             len = len - half - 1;
14         }
15     }
16     return first;
17 }

 

  lower_bound

  这一库函数的定义是:在当前传来的非降序列两个地址间,return第一个大于等于当前传来的值的地址

  使用格式:lower_bound(a+1,a+n+1,num);

  各数组意义的定义和上面的基本一致

  库函数代码如下

 1 int lower_bound(int *array, int size, int key)
 2 {
 3     int first = 0, middle;
 4     int half, len;
 5     len = size;
 6 
 7     while(len > 0) {
 8         half = len >> 1;
 9         middle = first + half;
10         if(array[middle] < key) {     
11             first = middle + 1;          
12             len = len-half-1;       //在右边子序列中查找
13         }
14         else
15             len = half;            //在左边子序列(包含middle)中查找
16     }
17     return first;
18 }

  2.关于个人代码习惯

  这里有两种,分别是preyW和szl两神犇的不同二分写法习惯,在这里供参考

 1 int prey_BS(int l, int r, int key)
 2 {
 3     while( l < r - 1 )
 4     {
 5         m = (l+r)>>1;
 6         if(a[m] < key)  
 7             l = m + 1;
 8         else
 9             r = m;
10     }
11     return l;
12 }
 1 int zl_BS(int l, int r, int key)
 2 {
 3     int ans;
 4     while(l < = r)
 5     {
 6         m = (l + r)>>1;
 7         if(a[m] < key)
 8             l = middle + 1;
 9         else{
10             r = m - 1;
11             ans = r;
12         }
13     }
14     return ans;
15 }

  这两种方法可能和神犇亲手写的有出入,不过大概就是这样

  总的来说,二分还是一种解题利器,如果对于写法不够明确的看官,可以用以上的STL以及神犇写法来代替自己原本的,可能效果会更好

  然后例题就是全部openjudge以及codevs的二分题

  祝大家刷的开心

posted @ 2016-10-17 18:51  PencilWang  阅读(195)  评论(0编辑  收藏  举报