整数域
2种边界
[l,r] (左闭又闭 容易理解最好用)
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<iostream> using namespace std; int main(){ int l,r; int n; cin>>n; while(l<=r){ int mid=(l+r)>>1; if( calc(mid) < n ) l=mid+1; else r=mid-1; } return 0; }
|
[l,r+1) (左闭右开 )
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<iostream> using namespace std; int main(){ int l,r; int n; cin>>n; while(l<r){ int mid=(l+r)>>1; if( calc(mid) < n ) l=mid+1; else r=mid; } return 0; }
|
实数域
设置一个需要的精度 eps( 需要确定到小数点的后几位 1ek
) 以 l+eps<r
作为循环条件
1 2 3 4 5 6 7 8 9 10 11 12
| #include<iostream> using namespace std; int main(){ double l,r; cin>>l>>r; while( l+eps< r ){ double mid=(l+r)/2; if( calc(mid) ) ans=mid,l=mid; else r=mid; } return 0; }
|
如果一个问题的结果具有单调性(结果在所给出的定义域中),那么也可以用二分寻找结果
例题:
N本书排成一行,第i本的厚度为$a_i$,把它们分成连续的M组,使T最小化,T是厚度之和最小的一组,求最小的T是多少?
思路:在[0,总厚度]中二分,如果按照二分厚度可以分成m组(大于m也行)那么记录并且维护最小t
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<iostream> using namespace std; const int maxn=10000; int a[maxn]; int n,m; bool valid(int k){ int group=1,rest=k; for(int i=1;i<=n;i++){ if(rest >= a[i]) rest-=a[i]; else group++,rest=k-a[i]; } return group<=m; } int main(){ int ans=0; cin>>n>>m; int sum=0; for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; int l=0,r=sum; while(l<=r){ int mid=(l+r)>>1; if( valid(mid) ) ans=mid,r=mid-1; else l=mid+1; } cout<<ans; return 0; }
|