二分答案是參數搜索的一個改善。
是這樣,對於一個問題,若是它的答案具備單調性質(即若是i不可行,那麼大於i的解都不可行,而小於i的解有可能可行),進而用二分的方法枚舉答案,再判斷答案是否可行,直到求到符合條件爲止。
例如:問題的答案範圍是1到w之間的一個整數,求最小解,那麼咱們設s=1,t=w,以後mid=(s+t)整除2。而後判斷當解是mid的時候這個問題能不能解決,若是能解決則和最優解比較,而且範圍縮小到s到mid-1之間(由於即便這個範圍沒有解,那麼mid是最小解);若是不能解決問題,則最小解確定比mid要大,則範圍縮小到mid+1和t之間。如此反覆知道s=t時判斷完結束。
這時候那個記錄最優解的變量必定記錄的是可以達到的最優解。
羅嗦了這麼多,簡單來講就是假設一個答案,而後判斷是否可行,而且不斷縮小範圍。
二分枚舉答案的時間複雜度是O(log2 n),而判斷時間是O(K)的話總的時間複雜度是O(Klog2 n)若是某個問題符合這個性質而且K比較小的話這個方法至關實用。ide
舉個例子:spa
k序列和code
【問題描述】blog
對於一個給定的序列,將其分爲k個部分,求各部分和的最大值的最小值。input
【問題分析】it
可採用二分答案的思想,設出一個答案ans,循環將和不超過ans的幾個數分爲一部分。直到最後若能夠分爲k部分則減少上界,反之增長下界。直到肯定答案。io
AYYZOJ 1588event
1 var 2 n,k,i,p,l,r,m,s:longint; 3 a:array[1..100005] of longint; 4 begin 5 readln(n,k); 6 for i:=1 to n do 7 begin 8 read(a[i]); 9 inc(r,a[i]); 10 end; 11 while r-l>1 do 12 begin 13 m:=(l+r) shr 1; 14 s:=0; p:=0; 15 for i:=1 to n do 16 if s+a[i]<=m then s:=s+a[i] 17 else begin inc(p); s:=a[i]; end; 18 if p+1>k then l:=m else r:=m; 19 end; 20 writeln(r); 21 end. 22 // 65分。。 23 原程序輸出 r ----> 65 24 更改輸出爲 l+1 ----> 65 25 原程序循環條件 while r-l>1 do if p+1>k then l:=m else r:=m; 26 改成 while l<r do if p+1>k then l:=m+1 else r:=m-1; ------> 55 27 只改爲 while l<r 死循環
令我鬱悶的是不知上面的程序哪裏不對,只有65分。function
1 var 2 l,r,mid,n,m,i:longint; 3 a,b:array[1..100000] of longint; 4 function check(p:longint):boolean; 5 var 6 i,pre,tot:longint; 7 begin 8 tot:=m; 9 pre:=0; 10 i:=1; 11 while i<=n do 12 begin 13 if pre+a[i]<=p then 14 begin 15 pre:=pre+a[i]; 16 inc(i); 17 end 18 else 19 begin 20 pre:=0; 21 dec(tot); 22 if tot=0 then exit(false); 23 end; 24 end; 25 exit(true); 26 end; 27 begin 28 readln(n,m); 29 r:=0; 30 for i:=1 to n do 31 begin 32 readln(a[i]); 33 inc(r,a[i]); 34 end; 35 l:=0; 36 while l<r do 37 begin 38 mid:=(l+r)>>1; 39 if check(mid) then r:=mid else l:=mid+1; 40 end; 41 writeln(l); 42 end.
COGS 917 劃分序列 class
交上一樣的程序就過了。。
1 var 2 n,k,i,p,l,r,m,s:longint; 3 a:array[1..100000] of longint; 4 begin 5 assign(input,'seqa.in'); 6 reset(input); 7 assign(output,'seqa.out'); 8 rewrite(output); 9 readln(n,k); 10 for i:=1 to n do 11 begin 12 read(a[i]); inc(r,a[i]); 13 end; 14 while r-l>1 do begin 15 m:=(l+r) shr 1; 16 s:=0; p:=0; 17 for i:=1 to n do 18 if s+a[i]<=m then s:=s+a[i] 19 else begin inc(p); s:=a[i]; end; 20 if p+1>k then l:=m else r:=m; 21 end; 22 writeln(r); 23 close(input); 24 close(output); 25 end.