二分法进阶

最后都变了- 提交于 2020-01-22 20:17:33

在算法竞赛题目中,有两种题型:整数二分、 实数二分。

  1. 整数域上的二分, 注意终止边界、左右区间的开闭情况, 避免漏掉答案或者死循环
  2. 实数域上的二分, 需要注意精度问题。

之前迷惑了好久的边界问题,在这里总结一下:

整数二分:

  1. [left,right][left,right]:分割 [left,mid1][left,mid-1]midmid[mid+1,right][mid+1,right],循环条件 left<=rightleft<=right
  2. [left,right)[left,right):分割 [left,mid)[left,mid)midmid[mid+1,right)[mid+1,right),循环条件 left<rightleft<right

实数二分:

  1. [left,right)[left,right):分割[left,mid)[left,mid)[mid,right)[mid,right)

【整数二分】

[left,right][left,right] 模板:

bool check(int mid)
{
	if(根据题意判断)	return true; 
	else	return false;
}

int left, right, ans;
while(left <= right)
{
	int mid = left+(right-left)/2;	//二分
	if(check(mid))	//根据题意检查条件,如果成立
	{
		ans = mid;		//记录答案
		left = mid + 1;		//移动left(或right)
	}
	else
	{
		right = mid - 1;	//移动right(或left)	
	}
}

[left,right)[left,right) 模板:

bool check(int mid)
{
	if(根据题意判断)	return true; 
	else	return false;
}

int left, right, ans;
while(left < right)
{
	int mid = left+(right-left)/2;	//二分
	if(check(mid))	//根据题意检查条件,如果成立
	{
		ans = mid;		//记录答案
		left = mid + 1;		//移动left(或right)
	}
	else
	{
		right = mid;	//移动right(或left)	
	}
}

所以, 二分法的难点在于如何建模和check()条件,其中可能会套用其他算法或者数据结
构。

【实数二分】

实数域上的二分比整数二分简单。

模板:

//精度。若保留k位小数,eps一般取10^-(k+2)
const double eps = 1e-7;	//如果下面用for,可以不要eps

bool check(double mid)
{
	if(根据题意判断)	return true;
	else	return false;
}

double BinSearch(double left, double right)
{
	//for(int i = 0; i < 100; i++)
	while(right - left > eps)
	{
		double mid = left+(right-left)/2;
		if(check(mid))	left = mid; 	//根据题意判定,然后继续二分
		else	right = mid;
	}
	return left;	//right也对 
}

其中, 循环用 22 种方法都可以:

如果用 forfor 循环, 由于循环内用了二分, 执行 100100 次, 相当于实现了 1/21001/2^{100} 的精度, 一般比 epseps 更精确。

forfor 循环的 100100 次, 比 whilewhile 的循环次数要多。 如果时间要求不是太苛刻, 用 forfor 循环更
简便。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!