策略性跳躍的 二分搜尋

2021-10-23 17:11:38 字數 4112 閱讀 7390

以下是我結合 《挑戰程式設計競賽》的二分內容的一些個人總結:

1.2 判斷乙個解是否可行

1.3 最大化最小值問題

1.4 最大化平均值

2.二分習題

我們常見的二分查詢,只需要找到乙個符合的值就行。

//預設公升序

intbinarysearch

(int find,

int length,

int value)

return-1

;}

int

lower_bound

(int a,

int length,

int k)

else right = mid -1;

//滿足條件縮小範圍

}return left;

}

這是我在《挑戰程式設計競賽》上看到的區間二分寫法,看起來國外人比較喜歡這種區間寫法,既適用於int,也適用於double類的二分:

int

lower_bound

(int a,

int length,

int k)

else ub = mid;

//滿足範圍變為(lb,mid]

}return ub;

//此時lb + 1 = ub

}

仔細看同乙個查詢功能,不同的寫法返回的是左界還是右界也並不統一,需要判斷一下。

如果希望一勞永逸的話,不妨加乙個變數儲存最後一次可行解:

int

lower_bound

(int a,

int length,

int k)

else

if(a[ub]

> num)

return-1

;//都小的情況

return res;

//最後乙個可行解

}

二分法除了用來查詢以外,還可以適用一些優化求解問題:比如,求滿足某個條件c(x)的最小/大 值一類問題

這裡給出一道《挑戰》例題:

cable master

題意:有n條繩子 (<=10000),長度分別為li (<=100000),從其中切割出k條長度相同的繩子,每條繩子最長為多少,結果保留2位小數

這道題結合之前提到的:「求滿足某個條件c(x)的最小/大 值一類問題」

上述題可以轉化有:c(x):能否獲得k條長度為x的繩子

然後我們利用二分的思想:

切割繩子可能的長度(0,100000)

若c(mid)滿足,則切割繩子的範圍在[mid,ub]中(因為求最大滿足)

不斷縮小範圍至區間精度足夠輸出結果

重點就在c(x)的判斷了:能否獲得k條長度為x的繩子 == 遍歷每個繩子長度 / x 求和,和 >=k 即滿足 時間複雜度為o(n),二分複雜度為o(logn) == o(nlogn)綽綽有餘

還有一些細節就是:

double資料的二分,最終結果的精度要求可能有一些限制,具體看關鍵**:

這裡涉及到double使用區間二分就很自然。

//《挑戰》解法

//判斷是否滿足條件

boolc(

double x)

//以x長度每條繩

void

solve()

printf

("%.2f\n"

,floor

(ub *

100)

/100);

//用floor函式擷取,不然是%.2f 4舍5入}/*

這題選lb做結果會wa,ub不會,估計是double的精度問題,測試資料過不了lb

可以使用int二分將千公尺轉換成公尺,對整數進行二分,取lb能a,避免double造成的精度問題

*/

最大化最小值 && 最小化最大值問題 == 是一類題

通常為: 希望滿足某個條件c(x)的 x盡量大 或者 盡量小

例題 aggressive cows

農夫約翰建造了乙個新穀倉,裡面有n (2 <= n <= 100,000)個畜欄。檔位沿直線排列在x1,…,xn (0 <= xi <= 1,000,000,000) 他的奶牛(2 <= c <= n)不喜歡這個穀倉的布局,一旦被放進去,它們就會變得好鬥。為了防止奶牛互相傷害,fj想把奶牛分配到牛欄中,使最近兩頭奶牛之間的距離就盡可能的大。請問最大的最近距離是多少?

很明顯的最大化最小值問題:

令c(x):使每條牛之間的間距不小於x是否可行

初始區間為0~inf,用二分不斷縮減可能的最短距離區間距離,至只有乙個值

int d[max_n]

;int n,k;

//n 畜欄 k 牛

boolc(

int x)

return

true;}

intmain()

sort

(d,d+n)

;int lb =

0,ub = inf;

while

(ub - lb >1)

printf

("%d\n"

,lb);}

}

類似的最小化最大值問題: c(x) :滿足什麼什麼的最大值條件

int lb =

0,ub = inf;

while

(ub - lb >1)

這一類題大多是:

有n個重量為wi,價值為vi的物品,從中選出k件使得單位重量的價值最大,即:

γ (k

)=∑0

nvi/

wi

.\gamma(k) = \sum_0^\n v i /wi\,.

γ(k)=0

∑n​v

i/wi

.我們令c(x):使單位重量的價值不小於x,儘管wi,vi可能為int,x卻為double~那麼有: ∑0n

vi/w

i≧x.

\sum_0^\n v_i / w_i \geqq x\,.

0∑n​vi

​/wi

​≧x.

∑ 0n

(vi−

wi∗x

)≧0.

\sum_0^\n (v_i - w_i * x) \geqq 0\,.

0∑n​(v

i​−w

i​∗x

)≧0.

c(x)轉變為 :選取按 (v - w * x) 排序的前k大的物品的和,大於等於0 是否成立

偽**:

int n,k;

int w[n]

,v[n]

;double y[n]

;boolc(

double x)

sort

(y,y + n)

;double sum =

0.0f

;for

(int i =

0;i < k;

++i)

return sum >=0;

}void

solve()

printf

("%.2f\n"

,ub)

;//lb也行,主要看精度卡的怎麼樣

}

收錄於《挑戰程式設計競賽》

river hopscotch poj 3258

monthly expense poj 3273

drying poj 3104

cow acrobats poj 3045

可以不做,貪心題,二分其實就是半完全貪心

dropping tests poj 2976

k best poj 3111

matrix poj 3685

median poj 3579

telephone lines poj 3662

末地傳送門

5 9 二分搜尋樹的順序性

二分搜尋樹當做查詢表的一種實現。我們使用二分搜尋樹的目的是通過查詢 key 馬上得到 value。二分搜尋樹還能回答哪些問題呢?這些問題都和順序相關。minimum,maximum successor,predecessor 這兩個元素在二分搜尋樹的 key 中必須存在 floor 地板 ceil ...

Java 二分搜尋 二分查詢

對陣列元素進行逐個查詢顯然是費時費力的工作,我們可以使用一些方法快速地搜尋出陣列中元素的指定位置.接下來我們介紹一種方法 二分搜尋法 二分搜尋法充分利用了元素間的次序關係.基本思想 將n元素分成個數大致相同的涼拌,取arr n 2 與欲查詢的x做比較,如果 下面將採用兩種方式 遞迴 非遞迴 來展示二...

二分檢索用途及複雜性 二分搜尋演算法

介紹 在電腦科學中,二分搜尋 英語 binary search 也稱折半搜尋 英語 half interval search 對數搜尋 英語 logarithmic search 是一種在有序陣列中查詢某一特定元素的搜尋演算法。搜尋過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜尋過程...