1.关于二分的两种写法
一种是 while(left<right)
{
if()
left=mid+1;
else right=mid;
}
ans=left;
这是我比较喜欢的一种
还有一种是while(left<=right)
{
if()
left=mid+1;
else right=mid-1;
}
ans=mid;
注意两种的ans是不同的
2. 假如二分要求的答案是个唯一确定的值,这样是不容易错的,但当有个区间是符合要求的,我们要求这个符合要求的区间的最大值或者最小值,这个时候就容易出错了
而二分也经常用来求最大的最小值和最小的最大值
poj3258 二分求最大的最小值
不出错关键要理解这个mid,此时我们要求这个可行区间的最大值,mid其实是小于这个上限但很接近它的一个数,所以if(b[i]<=mid) 而不是<
二分统计后,if内的条件判断不取等号是因为,这样做后right会小于这个上限,使结果过小
#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[50600],b[50600];
int main ()
{
int l,n,m;
while(scanf("%d%d%d",&l,&n,&m)!=EOF)
{
a[0]=0;
int left=1000000000;
int right=-1;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
a[++n]=l;
for(int i=n;i>=1;--i)
{
a[i]=a[i]-a[i-1];
if(left>a[i])
left=a[i];
if(right<a[i])
right=a[i];
}
int mid;
while(left<right)
{
mid=(left+right)/2;
int now=0;
int p=0;
for(int i=1;i<=n;++i)
b[i]=a[i];
for(int i=1;i<=n;++i)
{
if(b[i]<=mid) // 重点在取等于!
p++,b[i+1]+=b[i];
}
if(p>m)
right=mid;
else left=mid+1;
}
printf("%d\n",left);
}
return 0;
}
poj 3273 二分求最小的最大值
此时我们要求这个可行区间的最小值,mid其实是大于这个下限但很接近它的一个数,当mid符合要求时,即=m的时候
可以把right=mid,因为我们要求的是最小值
#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[100600];
int main ()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int left=-1,right=0;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
right+=a[i];
if(left<a[i])
left=a[i];
}
int mid;
while(left<right)
{
mid=(left+right)/2;
int cnt=0;int now=0;
for(int i=1;i<=n;++i)
{
if(now+a[i]>mid) // 不取等于!
{
cnt++;
now=a[i];
}
else // 即if(now+a[i]<=mid)
{
now+=a[i];
}
}
if(now)
cnt++;
if(cnt<=m)
right=mid;
else left=mid+1;
}
printf("%d\n",left);
}
return 0;
}