從乙個NOI題目再學習二分查詢。

2022-04-07 08:00:04 字數 3382 閱讀 6659

二分法的基本思路是對乙個有序序列(遞增遞減都可以)查詢時,測試乙個中間下標處的值,若值比期待值小,則在更大的一側進行查詢(反之亦然),查詢時再次二分。這比順序訪問要少很多訪問量,效率很高。

設:low,hight,mid均為整型。以在乙個降序arr[5]=中查詢k=4時的下標為例,取low=0,hight=4,則mid=low+(hight-low)/2=2(若無溢位可直接相加取半),此時arr[mid]=2小於k,這時需要向值更大的一側(左側)查詢,所以low不變,hight=mid=2,再次拆半查詢,mid=low+(hight-low)/2=2=1,此時arr[mid]=4等於k。找到結果。

這就是二分查詢或者叫折半查詢的基本思想。因為**比較簡單,所以無需用效率較低的迭代來實現:

int mid;

while(true)else

}

**看起來就是這樣的。現在來考慮這樣乙個問題,若上述查詢中,k=3將會出現什麼情況:當mid=1即arr[mid]=4時,大於k,而後出現**無法收斂。實在是太糟糕了,所以我們要加上乙個收斂的條件,以及沒有找到結果時的返回:

int mid;

while(lowk)else

}return -1;

好吧,這看起來比較完美了。現在,我們總結一下:

在二分查詢中,若沒有找到恰好的結果(很多時候我們不知道我們要的結果的確切值),while的退出條件即收斂條件,這個條件首先應滿足low現在看另外乙個典型的例子:若函式f(x)在區間[a,b]內的單調,且f(a)<0,f(b)>0,求在該區間內的f(0)的值,精確到1e-10。此時,我們不知道要求的確切值,那麼只能利用while的收斂條件:

double k=1e-10;

double mid;

//k/=100;

while(hight-low對於這個單調遞增函式,當f(mid)比0小的時候,我們增加下限,向上查詢。收斂時要求mid和實際解y之間差距不超過k,即當mid-k<=y<=mid+k時退出,最糟糕的時候low或hight正好為解,此時另一方跨越k距離正好達到精度,即hight-low=k時退出,迴圈條件為hight-low下面可以說一下這個煩惱了我昨天一天,今天半上午的矩形分割了,這個問題現在長得是醬紫的:

總時間限制: 1000ms 記憶體限制: 65536kb

描述平面上有乙個大矩形,其左下角座標(0,0),右上角座標(r,r)。大矩形內部包含一些小矩形,小矩形都平行於座標軸且互不重疊。所有矩形的頂點都是整點。要求畫一根平行於y軸的直線x=k(k是整數) ,使得這些小矩形落在直線左邊的面積必須大於等於落在右邊的面積,且兩邊面積之差最小。並且,要使得大矩形在直線左邊的的面積盡可能大。注意:若直線穿過乙個小矩形,將會把它切成兩個部分,分屬左右兩側。

輸入第一行是整數r,表示大矩形的右上角座標是(r,r) (1 <= r <= 1,000,000)。

接下來的一行是整數n,表示一共有n個小矩形(0 < n <= 10000)。

再接下來有n 行。每行有4個整數,l,t, w 和 h, 表示有乙個小矩形的左上角座標是(l,t),寬度是w,高度是h (0<=l,t <= r, 0 < w,h <= r). 小矩形不會有位於大矩形之外的部分。

輸出輸出整數n,表示答案應該是直線 x=n。 如果必要的話,x=r也可以是答案。

樣例輸入

1000

21 1 2 1

5 1 2 1

樣例輸出

5

這個描述可能理解起來有點困難。翻譯一下:

乙個左下角在(0,0)寬度為r的正方形範圍內,有若干不重疊的小矩形(x,y,w,h均為整數,其中w,h>0),要求在該範圍內畫一條x=k的直線滿足如下要求:

0、k為正整數。

1、在該直線左側的小矩形的面積和大於等於在該直線右側小矩形的面積和。若小矩形被分割,則左側部分計入左面面積和,右側部分計入右側面積和。

2、滿足0、1的前提下,盡量靠右側分割。

這個問題要求用二分法進行解答。很容易想到二分所求的結果就是左右面積差,但是這存在兩個問題:

1、k取整時,如何收斂。即正好分割為左右相等時,很多情況下要把乙個單位距離分割為兩份,亦即切分若干小矩形。

2、盡量靠右側分割。即直線正好落在一段沒有小矩形的位置,此時右面若干單位上也沒有小矩形,k如何盡量大。

先來看第乙個問題:這屬於我們前面提到的精度問題的類似問題——low,hight逼近解到什麼程度收斂。顯而易見,要求k為整數時,low+1=hight即收斂,所以迴圈條件為low+11。這樣,二分結束時的low就是最小k值。

然後裡解決問題二:既然k落在可能解上,那麼只需要計算當前k值時左右面積差s,若右移k面積依然是s,那麼繼續右移,直到右移一次之後,左右面積差大於s即找到最大k。

ps:low不可能是解,因為若直線分割小矩形,則左移導致左側面積減小,不滿足題意;即使在直線不分割小矩形,也不滿足盡量靠右原則。

這就是我對這個題目的理解,不過我通過的**在解決問題1時思路不同:

一定有乙個位置x可以使得左右小矩形面積差為0,但x不能用整數表示。所以,我使用了double來表示。在糾正了若干錯誤,提交無數次之後,得了9分……咳咳…………。這就是那份**:

#include#include

#include

using

namespace

std;

struct

srect;

double meval(srect rect,int rc,double

x)else

if(rect[i].right<=x)

else

}return ls-rs;

}double mbsearch(srect rect,int rc,double low ,double

hight)

else

if(d>0

)else

}return

mid;

}int

main()

x=ceil(mbsearch(rect,rc,0

,br));

s=meval(rect,rc,x);

while(s=meval(rect,rc,x+1) && x

cout

<}

乍一看是一點問題也沒有,於是在煎熬一天半之後,又煎熬了幾分鐘。發現評價函式返回的double值竟然…………不想等。好吧,我知道你精度挺高,但達不到1就是1的程度,修改一下比較條件:

while(abs(s-meval(rect,rc,x+1))<=1e-15 && x

x++;

}用double的最大精度限制一下就10分了。當然,用double效率要比用int要低,雖然我用了乙個int(low)沒有取真正的精確值。而且這份**還有很明顯的需要優化的部分:low,hight的初始值應該是所有小矩形的min(left)和max(right)——搜尋的範圍越小迭代次數越少。

乙個二分查詢程式

原問題來自 http topic.csdn.net u 20090826 18 c08b69e8 ce22 4427 8687 ffb53e380437.html 問題如下 有一連串字母,由且必由若干個 a,b,c,d,e 組成,順序是 若干個 a,若干個 b,若干個 c,若干個 d,若干個 e 即...

手寫乙個二分查詢

二分查詢演算法思想 又叫折半查詢,要求待查詢的序列有序。每次取中間位置的值與待查關鍵字比較,如果中間位置的值比待查關鍵字大,則在前半部分迴圈這個查詢的過程,如果中間位置的值比待查關鍵字小,則在後半部分迴圈這個查詢的過程。直到查詢到了為止,否則序列中沒有待查的關鍵字。class erfenfa sor...

python實現乙個二分查詢

二分查詢 二分查詢也稱折半查詢 binary search 它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列 查詢過程 首先,假設表中元素是按公升序排列,將表中間位置記錄的關鍵字與查詢關鍵字比較,如果兩者相等,則查詢成功 否則利用中間位置記錄將表...