如何写对二分法

这几天刷题,写了几次二分,无一例外都写炸了,要么多一个,要么少一个,要么就死循环。。。。

于是总结一下写二分的经验和教训。。。

请看下面一段代码:

int bsearch(int lf,int ri){
	if(lf==ri)return lf;
	int mid=(lf+ri)/2,ans=0;
	if(mid==lf||mid==ri) return mid;
	int pos=0<pre class="cpp" name="code">int bsearch(int lf,int ri){
	//if(lf==ri)return lf;
	int mid=(lf+ri)/2,ans=0;
	if(mid==lf||mid==ri){
		int ansl=0,ansr=0,pos=0;
		for(int i=1;i<=n+1;i++)
			if(d[i]-d[pos]<lf) ansl++;
			else pos=i;
		pos=0;
		for(int i=1;i<=n+1;i++)
			if(d[i]-d[pos]<ri) ansr++;
			else pos=i;
		if(ansr<=m)return ri;
		else return lf;
	}
	int pos=0;
	for(int i=1;i<=n+1;i++)
		if(d[i]-d[pos]<mid) ans++;
		else pos=i;
	if(ans>m) return bsearch(lf,mid);
	return bsearch(mid,ri);
}
 

这是NOIP2015D2T1跳石头。本来我没有加第四行的代码,但是不加的话就会陷入死循环,加了的话只得了60分。

忽略第四行代码,看一下求mid的过程,我只写了(lf+ri)>>1,而没有写(lf+ri+1)>>1;但是加上的话仍然死循环。

动态查一下错,发现当lf===4,ri==5时,求出的mid==5,然后由于除法向下取整,递归一直保持lf==4,ri==5,mid==5的状态。于是尝试将递归处改为,求mid时不+1:

	if(ans>=m) return bsearch(lf,mid-1);
	return bsearch(mid,ri+1);

然而结果是这样的

很明显,4459/4460是边界搞错,第二个点就TLE说明死循环

如果在求mid时加一,就变成了这个样子:

没有了死循环,但是边界还是搞错。

这时候可以特判一下,同时取消+1或-1之类的操作:

int bsearch(int lf,int ri){
	int mid=(lf+ri)/2,ans=0;
	if(mid==lf||mid==ri){
		int ansl=0,ansr=0,pos=0;
		for(int i=1;i<=n+1;i++)
			if(d[i]-d[pos]<lf) ansl++;
			else pos=i;
		pos=0;
		for(int i=1;i<=n+1;i++)
			if(d[i]-d[pos]<ri) ansr++;
			else pos=i;
		if(ansr<=m)return ri;
		else return lf;
	}
	int pos=0;
	for(int i=1;i<=n+1;i++)
		if(d[i]-d[pos]<mid) ans++;
		else pos=i;
	if(ans>m) return bsearch(lf,mid);
	return bsearch(mid,ri);
}
于是成功AC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值