二分+三分

二分

理解

  • while(left<=right),答案一定在[left,right]中。
  • 思想有兩種
  1. 通過縮小範圍來快速找到目標數的位置(應用1)--- 找到答案終止循環
  2. 不斷捨棄答案不可能存在的區間來逼近真實答案,若答案爲整數,則可以正好找到該答案,若爲實數則會找到在某個精度內的答案(應用2,3)--- 把循環全走一邊結束

 

STL中給出的函數

lower_bound

upper_bound

 

應用題型

  1. 查找(找到指定數字即可、有重複數字時查找第一個、找比指定數大的...)
  2. 求單調函數零點
  3. 最大化最小值、最小化最大值
  4. 快速冪

 

查找

1.查找指定數字

例題: Can you find it? HDU - 2141

  • 二分模板
int bsearch()
{
	int left = 0,right = n,mid;
	while(left<=right)
	{
		mid = left+(right-left)/2;
		if(a[mid]==x)
			return mid;
		else if(a[mid]<x)
			left = mid+1;
		else 
			right = mid-1;
	}
	return -1;
 } 

查找到就返回mid下標,沒找到就返回-1了。循環的終止是靠找到後return跳出,或者沒找到while判斷失敗結束。

模板的使用有幾處注意事項:

  1. 首先是mid = left+(right-left)/2,此處這麼寫是有原因的,若寫mid = (right+left)/2則在數組開的很大的時候,作爲下標,雖然數組本身下標可以用int 表示,但right和left相加容易int溢出。寫mid = left/2+right/2就更不行了,這個很有可能死循環,如left=1,right=1,mid=0(自己掉過的坑)。 
  2. 還有就是循環條件和left、right的變換方式要匹配,要麼就全按照模板這樣寫,還有其它種寫法,若是整數的搜索,按照模板沒問題的,因爲模板會遍歷到所有數。詳細解釋:轉載
  3. 沒有常數步進容易造成死循環,詳細解釋:轉載

二分法的查找過程就是二叉排序(查找、搜索)樹

 

求單調函數零點

例題:Can you solve this equation? HDU - 2199

這種應用不是找到真正的解,而是在一定的精度範圍內就可以了,所以循環的終止並不是靠a[mid] = x,而是靠while的條件如right-left<1e8,因爲結果一定是在這個區間內的,所以當結果可能的取值範圍在 1e8 說明精度就在 1e8 了,就可以結束了。

 

最小化最大值

例題:修路 CSU - 1023

這種二分的使用,實際上是有技巧的枚舉,答案爲已知區間的整數,所以就可以將這個區間內的所有整數全判斷一遍,但這種方法肯定就爆炸了,所以要在枚舉的同時帶技巧--二分是把肯定不成立的區間從可能解中刪去

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章