参考: 算法竞赛 , 这篇$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]$,如果二分终止后停留在扩展结点上则无解
讲了这么多我觉得还是第一种做法最好了,考虑的要少很多: )
但是算法竞赛上就第一种没讲???