整数二分的正确打开方式

参考: 算法竞赛 , 这篇$Blog$

感觉二分一直迷迷糊糊,终于要来写一篇小结辣

 总的来说有两种写法:

  1.记录答案

  2.不记录答案

 细分有三种:

  1.记录答案(左右边界哪个是答案都差不多)

  2.不记录答案且找最小的合法解

  3.不记录答案且找最大的合法解(最易错的!!)

下面就来具体说说细分的三种

 1.记录答案

//找到最大的合法解

while
(l<=r) { int mid=(l+r)>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d ",ans);
//找到最小的合法解

while
(l<=r) { int mid=(l+r)>>1; if(check(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d ",ans);

 2.不记录答案且找最小的合法解

while(l<r)
{
    int mid=(l+r)>>1;
    if(check(mid))r=mid;
    else l=mid+1;
}
printf("%d
",l);

 3.不记录答案且找最大的合法解

$Attention!$这里一定是$mid=(l+r+1)>>1$

考虑这样一种情况:$r=l+1,mid=(l+r)>>1=l$,$l$合法,$l=mid=l$,于是陷入死循环

while(l<r)
{
    int mid=(l+r+1)>>1; //!Attention!
    if(check(mid))l=mid;
    else r=mid-1;
}
printf("%d
",l);

注意点与拓展

1.不同的形式采取相应的$mid$取法

2.采取$>>1$而不是$/2$.这是因为右移运算是向下取整,而整数除法是向$0$取整,在二分值域包含负数时出错.

3.(对于后面两种做法而言)处理二分中的无解情况: 把最初的二分区间$[1,n]$扩展成$[0,n+1]$,如果二分终止后停留在扩展结点上则无解

讲了这么多我觉得还是第一种做法最好了,考虑的要少很多: )

但是算法竞赛上就第一种没讲???

光伴随的阴影
原文地址:https://www.cnblogs.com/forward777/p/11274599.html