• lower_bound()

    试图在已排序的 [first, last) 中寻找元素 value。返回一个迭代器,指向第一个“不小于 value”的元素,如果 value 大于 [first, last)内的任何一个元素,则返回 last。实际上,它返回“在不破坏顺序的情况下,可插入 value 的第一个合适位置”。

  • upper_bound()

    试图在已排序的 [first, last) 中寻找元素 value。返回一个迭代器,如果 value 存在,迭代器将指向最后一个 value 的下一位置。实际上,它会返回“在不破坏顺序的情况下,可插入 value 的最后一个合适位置”。也可理解为是第一大于 value 的元素的位置(不存在则返回 last)。

  • binary_search()

    返回值为 Bool 类型,如果 [first, last)内有等同于value的元素,便返回 true,否则返回 false。

  • equal_range()

    返回一个pair,其 first 成员是 lower_bound 返回的迭代器,second 成员返回的是 upper_bound 返回的迭代器。

二、二分搜索实现及分析

  二分搜索可分为整数型和小数型,其中整数型最为麻烦,边界条件、停止条件、区间初始化等容易搞混。

  整数二分

   以实现 lower_bound 为例,给定长度为$n$的单调不下降数列$a_{0},\cdots,a_{n-1}$和一个数$k$,求满足$a_{i}\geqslant k$的最小的$i$。不存在的情况下输出$n$。

 1 int n, k;
 2 int a[MAX_N];
 3 
 4 void solve() {
 5     int lb  = -1, ub = n;
 6     
 7     while (ub - lb > 1) {
 8         int mid = lb + (ub - lb) / 2;
 9         if (a[mid] >= k) {
10             // 如果mid满足条件,则解的存在范围变为(lb, mid]
11             ub = mid;
12         } else {
13             // 如果mid不满足条件,则解的存在范围变为(mid, ub]
14             lb = mid;
15         }
16     }
17 
18     print("%d\n", ub)
19 }

  分析:1. n = 0 那么此时 lb = -1,ub = n = 0,跳过 while 循环,输出 ub = n = 0,正确

     2. n = 1 那么此时 lb = -1,ub = n = 1,进入 while 循环, mid = 0。假如$a[0] \geqslant k$,那么 ub = 0,输出 ub = 0,否则 lb = 0,输出 ub = 0。

     3. 若 i 应为 0(即a[0] = k,数组左端点),那么 ub 会一直向左收缩(此过程中 lb 不变),直到 mid = 0,从而 ub = mid = 0。输出 ub = 0.

     4. 若 i 应为 n - 1(即a[n-1] = k,数组右端点),那么 lb 会一直向右收缩(此过程中 ub 不变),直到 lb = n - 2,lb + 2 = ub,此时 mid = n - 1,a[mid] == k, ub = n - 1,下一循环时条件不成立,输出 ub = n - 1.

     5. 若 i 应为 n(即数组中无 k),那么 lb 会一直向右收缩(此过程 ub 不变),直到 lb = n - 1,循环条件不成立,输出 ub = n。

    由上述分析可知,可解范围一直为 (lb, ub]。lb用来不断缩小范围。

  小数二分

  在使用二分搜索时,有必要设置合理的结束条件来满足精度的要求。1次循环可以把区间的范围缩小一半,100次的循环控制可以达到$100^{-30}$的精度范围。除此之外,可以把停止条件设置为$(ub-lb)>EPS$,指定一个区间的大小,要注意的是如果EPS取得太小,可能会因为浮点小数的精度问题而导致死循环,所以推荐第一种停止条件。

三、二分搜索思想的扩展

  分析 lower_bound() 函数,其搜索也可转化为“求满足某个条件$C(x)$的最小的$x$"这一问题。而$C(x)$即为$a_{i}\geqslant k$。对于任意满足$C(x)$的$x$,如果所有的${x}'\geqslant x$也满足$C({x}')$的话,我们就可以用二分搜索来求得最小的$x$。

  首先我们将区间的左端点初始化为不满足$C(x)$的值,右端点初始化为满足$C(x)$的值,然后每次取中点 mid,判断$C(mid)$是否满足并缩小范围,直到 (lb, ub] 足够小了位置,最后 ub 就是要求的最小值。最大化的问题也可以用同样的方法。

  1. 假定一个解并判断是否可行

 POJ No. 1064 Cable master

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

   令:条件$C(x):=$可以得到$K$条长度为$x$的绳子

   则问题变为求满足$C(x)$条件的最大的$x$。首先考虑区间的初始化问题。

   lb = 0;ub = INF

   长度的有效性肯定是不能超过$L_{i}$。那么我们直接设置这个值为INF(INT_MAX)。最小不能为0。

   现在的问题是是否可以高效的判断$C(x)$。由于长度为$L_{i}$的绳子最多可以切出$floor(L_{i} / x)$段长度为$x$绳子,因此

   $C(x)=$($floor(L_{i} / x)$的总和是否大于或等于$K$)。

  注意:此题为小数二分,较整数二分容易些;

     此题求的是满足条件的最大x,所以当满足条件时,lb = mid。所以才能求得最大值。

     结果显示2位小数,且不可四舍五入,处理方法为先乘上10的要显示的位数次方,取floor后再除以刚才乘上的因子。例如0.366,四舍五入为0.37,0.366 * 100 = 36.6,floor(36.6) = 36., 36. / 100 = 0.36。 

 1 #include <iostream>
 2 #include <vector>
 3 #include <math.h>  
 4 #include <limits.h>
 5 using namespace std;
 6 
 7 const int MAX = 100000 + 5;
 8 int N = 0, K = 0;
 9 double length[MAX];
10 
11 bool C(double x) {
12     int num = 0;
13     for (int i = 0; i < N; ++i) {
14         num += (int)(length[i] / x);
15     }
16     return num >= K;
17 }
18 int main(){
19     cin >> N >> K;
20     for (int i = 0; i < N; ++i) {
21         cin >> length[i];
22     }
23 
24     double lb = 0, ub = INT_MAX;
25     for (int i = 0; i < 100; ++i) {
26         double mid = (ub - lb) / 2 + lb;
27         if (C(mid))
28             lb = mid;
29         else
30             ub = mid;
31     }
32 
33     printf("%.2f\n", floor(lb * 100) / 100);
34     system("pause");
35     return 0;
36 }
View Code

相关文章: