以下是我結合 《挑戰程式設計競賽》的二分內容的一些個人總結:
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
∑nv
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∑nvi
/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 是一種在有序陣列中查詢某一特定元素的搜尋演算法。搜尋過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜尋過程...