之前一直都没有想清楚整数的二分到底是要打算怎么搞。
首先约定二分的区间为 $[l,r]$ 闭区间。
看一下下面这个实现,由于我们的约定,所以l与r都要取能取到的(合法的)值。
#include<bits/stdc++.h> using namespace std; int n; //找大于等于n的最小的m bool ok(int m){ return m>=n; } int main(){ while(~scanf("%d",&n)){ int l=1,r=1000000,m,ans; while(1){ m=(l+r)>>1; printf("%d ",m); if(m==l){ //边界情况 if(ok(l)){ //假设要求最小值,要先判断l ans=l; } else if(ok(r)){ //l不行再判断r,不能直接返回,因为不能确定答案是l或r其中之一 ans=r; } else{ ans=-1; } break; } if(ok(m)){ //假设要求最小值,m满足条件则去找更小的 r=m; } else{ //m不满足条件,排除掉 l=m+1; } } printf("ans=%d ",ans); } }
之前为什么会觉得边界条件是 $l$ 和 $r$ 相差为1,其实边界条件是 $l$ 和 $r$ 重合。其上一步的条件是 $l$ 与 $m$ 重合而 $l$ 和 $r$ 相差为1,此时若 $m$ 满足条件则 $r=m$ 收缩至 $l$ ,否则 $l=m+1$ 扩大至 $r$ 。所以这才是正确的写法。但是上面这样写完全足够了。下面是假设答案一定存在在 $[l,r]$ 中任意一个整数中。
#include<bits/stdc++.h> using namespace std; int n; //找大于等于n的最小的m bool ok(int m){ return m>=n; } int main(){ while(~scanf("%d",&n)){ int l=1,r=1000000,m; while(l<r){ m=(l+r)>>1; printf("%d ",m); if(ok(m)){ //假设要求最小值,m满足条件则去找更小的 r=m; } else{ //m不满足条件,排除掉 l=m+1; } } printf("ans=%d ",l); } }