二分答案模板及二分答案問題講解


二分答案

!閱讀須知||閱讀本博文前筆者認為讀者已經學會(或了解)了: 
1.基礎語言與算法 
2.標准二分法(二分思想) 
3.二分查找

定義

二分答案與二分查找類似,即對有着單調性的答案進行二分,大多數情況下用於求解滿足某種條件下的最大(小)值。

答案單調性

 

答案的單調性大多數情況下可以轉化為一個函數,其單調性證明多種多樣,如下:

  1. 移動石頭的個數越多,答案越大(NOIP2015跳石頭)。
  2. 前i天的條件一定比前 i + 1 天條件更容易(NOIP2012借教室)。
  3. 滿足更少分配要求比滿足更多的要求更容易(NOIP2010關押罪犯)。
  4. 滿足更大最大值比滿足更小最大值的要求更容易(NOIP2015運輸計划)。
  5. 時間越長,越容易滿足條件(NOIP2012疫情控制)。

可以解決的問題

  1. 求最大的最小值(NOIP2015跳石頭)。
  2. 求最小的最大值(NOIP2010關押罪犯)。
  3. 求滿足條件下的最小(大)值。
  4. 求最靠近一個值的值。
  5. 求最小的能滿足條件的代價。

代碼

為了保證解在二分搜索的區間里,故不同的問題有着不同(但相似)的寫法,讀者可以畫一個區間模擬一下~

題目解析

1.假定一個解並判斷是否可行(POJ 1064)

鏈接:http://poj.org/problem?id=1064

Cable master

Time Limit: 1000MS Memory Limit: 10000K


Description

Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Committee has volunteered and has promised to organize the most honest contest ever. It was decided to connect computers for the contestants using a "star" topology - i.e. connect them all to a single central hub. To organize a truly honest contest, the Head of the Judging Committee has decreed to place all contestants evenly around the hub on an equal distance from it. 
To buy network cables, the Judging Committee has contacted a local network solutions provider with a request to sell for them a specified number of cables with equal lengths. The Judging Committee wants the cables to be as long as possible to sit contestants as far from each other as possible.
The Cable Master of the company was assigned to the task. He knows the length of each cable in the stock up to a centimeter,and he can cut them with a centimeter precision being told the length of the pieces he must cut. However, this time, the length is not known and the Cable Master is completely puzzled. 
You are to help the Cable Master, by writing a program that will determine the maximal possible length of a cable piece that can be cut from the cables in the stock, to get the specified number of pieces.

Input

The first line of the input file contains two integer numb ers N and K, separated by a space. N (1 = N = 10000) is the number of cables in the stock, and K (1 = K = 10000) is the number of requested pieces. The first line is followed by N lines with one number per line, that specify the length of each cable in the stock in meters. All cables are at least 1 meter and at most 100 kilometers in length. All lengths in the input file are written with a centimeter precision, with exactly two digits after a decimal point.

Output

Write to the output file the maximal length (in meters) of the pieces that Cable Master may cut from the cables in the stock to get the requested number of pieces. The number must be written with a centimeter precision, with exactly two digits after a decimal point. 
If it is not possible to cut the requested number of pieces each one being at least one centimeter long, then the output file must contain the single number "0.00" (without quotes).

Sample Input

4 11
8.02
7.43
4.57
5.39

Sample Output

2.00

題目大意:有n條繩子,長度分別為L[i]。如果從他們中切割出k條長度相同的繩子的話,這k條繩子每條最長能有多長?(答案保留小數點后兩位,規定1單位長度的繩子最多可以切割成100份)。

分析:二分搜索最大長度x。我們令C(x)為可以得到K條長度為x的繩子,那么問題就變為了求滿足條件C(x)的最大的x。在區間初始化時,只需使用充分大的數inf(大於繩子的最大長度的二倍)作為上界即可:left=0,right=inf。那么現在的問題就變為了如何高效的判斷C(x)是否滿足。由於長度為L的繩子最多可以切割出floor(L/x)段長度為x的繩子,因子C(x)=floor(Li/x)的總和是否不小於k,他可以在O(n)的時間內判斷出來。

AC代碼:

 1 #include <cstdio>
 2 #include <cmath>
 3 using namespace std;
 4 const int M=10005;
 5 const double inf=200005.0;
 6 double L[M];
 7 int n,k;
 8 bool judge(double x)
 9 {
10     int num=0;
11     for(int i=0;i<n;i++)
12       num+=(int)(L[i]/x);
13     return num>=k;
14 }
15 void solve()
16 {
17     double left=0,right=inf;
18     for(int i=0;i<100;i++) //代替while(r>l) 避免了精度問題
19     { //1次循環可以把區間縮小一半,100次可以達到10^(-30)的精度
20         double mid=(left+right)/2;
21         if(judge(mid)) left=mid;
22         else right=mid;
23     }
24     printf("%.2f\n",floor(right*100)/100);
25 }
26 int main()
27 {
28     while(scanf("%d%d",&n,&k)!=-1)
29     {
30         for(int i=0;i<n;i++)
31           scanf("%lf",&L[i]);
32         solve();
33     }
34     return 0;
35 }

 

2.最大化最小值(POJ 2456)

鏈接:http://poj.org/problem?id=2456

 

Aggressive cows
Time Limit: 1000MS Memory Limit: 65536K 

Description

 

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). 

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

 

Input

 

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

 

Output

 

* Line 1: One integer: the largest minimum distance

 

Sample Input

 

5 3
1
2
8
4
9

 

Sample Output

 

3

 

Hint

OUTPUT DETAILS: 
FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3. 
Huge input data,scanf is recommended.

 

題意概述:農夫有c頭牛,n個隔間,c頭牛很躁動,很容易相互打架,因此農夫想把它們分得越遠越好,要你分配隔間使得相鄰兩頭牛的距離越遠越好,問你這c頭牛分割的最小距離的最大值。

解題思路:先對隔間的坐標排序,對於牛,最小距離是0,最大距離不會超過兩端兩頭牛的距離值,因此二分地查找分割距離的最大值,每次mid都judge一次,judge的時候貪心地放置牛,保證前i頭牛是符合這樣分割標准的。(二分如果拿捏不好精度,最好就直接暴力100次。)

AC代碼:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 #define INF 0x7fffffff
 5 #define maxn 100100
 6 using namespace std;
 7 int a[maxn];
 8 int n, c;
 9  
10 int judge(int m)
11 {
12     int last = 0;
13     for (int i = 1; i < c; i++)
14     {
15         int cur = last + 1;
16         while (cur < n && a[cur] - a[last] < m)
17             cur++;
18         if (cur == n)
19             return 0;
20         last = cur;
21     }
22     return 1;
23 }
24 int main()
25 {
26     while (scanf("%d%d", &n, &c) != EOF)
27     {
28         for (int i = 0; i < n; i++)
29             scanf("%d", &a[i]);
30         sort(a, a + n);
31         int l = 0, r = INF, m;
32         for (int i = 0; i < 100; i++)
33         {
34             m = l + (r - l) / 2;
35             if (judge(m))
36                 l = m;
37             else 
38                 r = m;
39         }
40         printf("%d\n", l);
41     }
42     return 0;
43 }

 

3.最大化平均值(POJ 2976)

鏈接:http://poj.org/problem?id=2976

 

Dropping tests
Time Limit: 1000MS Memory Limit: 65536K
 

Description

In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be

.

Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.

Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is . However, if you drop the third test, your cumulative average becomes .

Input

The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ ai ≤ bi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed.

Output

For each test case, write a single line with the highest cumulative average possible after dropping k of the given test scores. The average should be rounded to the nearest integer.

Sample Input

3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0

Sample Output

83
100

Hint

To avoid ambiguities due to rounding errors, the judge tests have been constructed so that all answers are at least 0.001 away from a decision boundary (i.e., you can assume that the average is never 83.4997).

 

題目大意:給定n個二元組(a,b),扔掉k個二元組,使得剩下的a元素之和與b元素之和的比率最大。

題目求的是 max(∑a[i] * x[i] / (b[i] * x[i]))   其中a,b都是一一對應的。 x[i]取0,1  並且 ∑x[i] = n - k;

那么可以轉化一下。  令r = ∑a[i] * x[i] / (b[i] * x[i])  則必然∑a[i] * x[i] - ∑b[i] * x[i] * r= 0;(條件1)

並且任意的 ∑a[i] * x[i] - ∑b[i] * x[i] * max(r) <= 0  (條件2,只有當∑a[i] * x[i] / (b[i] * x[i]) = max(r) 條件2中等號才成立)

然后就可以枚舉r , 對枚舉的r, 求Q(r) = ∑a[i] * x[i] - ∑b[i] * x[i] * r  的最大值,  為什么要求最大值呢?  因為我們之前知道了條件2,所以當我們枚舉到r為max(r)的值時,顯然對於所有的情況Q(r)都會小於等於0,並且Q(r)的最大值一定是0.而我們求最大值的目的就是尋找Q(r)=0的可能性,這樣就滿足了條件1,最后就是枚舉使得Q(r)恰好等於0時就找到了max(r)。而如果能Q(r)>0 說明該r值是偏小的,並且可能存在Q(r)=0,而Q(r)<0的話,很明顯是r值偏大的,因為max(r)都是使Q(r)最大值為0,說明不可能存在Q(r)=0了。

AC代碼:

 1 #include <iostream>
 2 #include <string>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <queue>
 6 #include <algorithm>
 7 using namespace std;
 8 const int maxn=1002;
 9 const double eps=1e-7;
10 int n,k;
11 double a[maxn];
12 double b[maxn];
13 int main()
14 {
15     while(cin>>n>>k)
16     {
17         if(n==0&&k==0)
18             break;
19         for(int i=0; i<n; i++)
20             scanf("%lf",&a[i]);
21         for(int j=0; j<n; j++)
22             scanf("%lf",&b[j]);
23 
24         double L=0.0;
25         double R=1.0;
26         double mid;
27 
28         double t[1004];
29 
30         while(R-L>eps)
31         {
32             mid=(R+L)*1.0/2;
33 
34             for(int i = 0; i < n; i++)
35                 t[i] = a[i] - mid * b[i];
36             sort(t, t + n);
37             double sum = 0;
38             for(int i = k; i < n; i++)
39                 sum += t[i];
40 
41             if(sum>0)
42                 L=mid;
43             else
44                 R=mid;
45         }
46         printf("%.0f\n",mid*100);
47     }
48     return 0;
49 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM