二分的几种简单应用——入门

---恢复内容开始---

说起二分,最基础的二分搜索算法就不用了吧(最难的还际应用啊感觉)……实现起来很简单,搜索区间不断减半……唔……嘛……简单甩个模板好了(●'◡'●)

下面开始学习二分的几种应用啦~~


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

一般用于求解判断条件较为简单的最大化和最小化的问题,不断缩小答案的区间。

怎么说呢……举个栗子好了

Cable master POJ - 1064 

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段绳子的长度,要求割出的段数,求每段的最大长度。
设bool型函数C(x):每段绳长为x时,可以割出K段绳子
那么题目就变成了求x的最大值,一开始将答案的区间范围设为(0,inf)
我们所要做的就是不断缩小答案所在的区间,直至区间的左右边界最接近。
用二分的方法,在C(x(mid))返回true时,说明x偏小(x>=最大值),让x变大,取原区间的左区间中点继续判断;
返回false时,说明x偏大,让x变小取原区间的左区间中点继续判断
直至区间缩小至最小,输出区间上界即可

不太明白为什么有的二分输出的是区间上界,有的是下界,有大佬给讲讲么

orz啊 ,WA了无数次……精度大坑啊……/(ㄒoㄒ)/~~记笔记记笔记
几个关于精度的问题:
①double转int的时候……记录每根绳子可以分为几段的时候crt=(int)(a[i]/x);加括号!!!不要忘了加括号!(敲黑板啊!)
②关于二分的循环次数,改用for(int i=0;i<100;i++),避免eps选取不当陷入死循环的问题,100次循环可以达到1e-30的精度范围
③floor(<cmath>)向下取整
④double型scanf用%lf,printf用%f!!!!
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
double n,a[10005],sum;
int k;
bool C(double x)
{
    int crt=0;
    for (int i = 0; i < n; i++)
        crt +=(int)(a[i] / x);
    return crt >= k;
}
int main()
{
    while (scanf("%lf%d", &n,&k)!=EOF)
    {
        sum = 0;
        for (int i = 0; i < n; i++)
        {
            scanf("%lf",&a[i]);
        }
        double l = 0, h = 0x3f3f3f3f;
        for(int i=0;i<100;i++)
        {
            double mid = (l + h) / 2;
            if (C(mid)) l = mid;
            else h = mid;
        }
        printf("%.2f
", floor(h * 100) / 100 );
    }
    return 0;
}

2.最大化最小值

道理跟上面差不多,最大化最小值或者最小化最大值的问题,通常可以用二分+贪心判断来解决

举个栗子,一起看一看

Aggressive cows POJ - 2456  

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.

题意:大概就是有n个牛舍,c头牛,给出牛舍的位置,问牛舍的安排方案中,牛与牛之间最小值最大是多少
判断函数:C(d):牛与牛之间的距离不小于d
贪心:①对牛舍的位置进行排序
           ②第一头放入x0
           ③第i头牛放入xj,第i+1头放入xj+d<=xk的最小的k中
           ④判断是否能安排好c头牛,是→增大d;否→减小d;
#include<iostream>
#include<stdio.h>
using namespace std;
int n,c,a[100010];
bool C(int d)
{
    int t = a[0],crt=1;
    for (int i = 1; i <n; i++)
    {
        if (a[i] - t >= d)
        {
            t = a[i];
            crt++;
            if (crt >= c) return true;
        }
    }
    return false;
}
int main()
{
    while (scanf("%d%d", &n,&c)!=EOF)
    {
        for (int i = 0; i < n; i++)
            scanf("%d",&a[i]);
        sort(a, a + n);
        int l = 0, h = a[n-1]-a[0];
        while(l<h-1)
        {
            int mid = (l + h) / 2;
            if (C(mid)) l = mid;
            else h = mid;
        }
        printf("%d
", l );
    }
    return 0;
}

3.最大化平均值

emmmmm……这类大部分都要先推出个式子呢……虽说是对平均值进行最大化的处理,但是却很难直接判断如何处理平均值……

举个栗子,体会体会

K Best    POJ - 3111 

Demy has n jewels. Each of her jewels has some value vi and weight wi.

Since her husband John got broke after recent financial crises, Demy has decided to sell some jewels. She has decided that she would keep k best jewels for herself. She decided to keep such jewels that their specific value is as large as possible. That is, denote the specific value of some set of jewels S = {i1, i2, …, ik} as

.

Demy would like to select such k jewels that their specific value is maximal possible. Help her to do so.

Input

The first line of the input file contains n — the number of jewels Demy got, and k — the number of jewels she would like to keep (1 ≤ kn ≤ 100 000).

The following n lines contain two integer numbers each — vi and wi (0 ≤ vi ≤ 106, 1 ≤ wi ≤ 106, both the sum of all vi and the sum of all wi do not exceed 107).

Output

Output k numbers — the numbers of jewels Demy must keep. If there are several solutions, output any one.

Sample Input

3 2
1 1
1 2
1 3

Sample Output

1 2

题意:给出n件物品的重量和价值,问从n件物品中取k件,取那些可以使单位重量的价值最大

唔,最容易想到的方法是,根据物品的单位重量的价值大小排序以后贪心的去取,但是这种方法是不正确的。

另外一种方法就是先确定最大的单位重量的价值(后面用s表示),然后取满足v-x*w>=0的物品。

因为最大的单位重量价值s=∑vi/∑wi(i为最优方案)>=x(其他方案的平均价值),稍作化简可以得到

∑(vi-x*wi)>=0也就是说最优方案的k件物品满足上述条件,我们只需要按每件物品的上式值排序,贪心的取前k件,判断其和是否>=0

一直在TLE……改天A了再贴代码


和上面完全一样的套路(为什么!为什么这个能过!上边那个过不了!!!)
 Dropping tests POJ - 2976 

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 ≤ aibi ≤ 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).

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
using namespace std;
struct grade{ double a,b;  };
int n, k;
grade g[1005];
double judge[1005];
//bool cmp(double x, double y) { return x > y; }
bool C(double x)
{
    double sum=0;
    for (int i = 0; i < n; i++)
        judge[i] = g[i].a - x*g[i].b;
    sort(judge, judge+ n);
    for (int i = k; i < n; i++)
        sum += judge[i];
    return sum > 0;
}
int main()
{
    while (~scanf("%d%d", &n, &k))
    {
        if (n == 0 && k == 0) break;
        for (int i = 0; i < n; i++)
            scanf("%lf", &g[i].a);
        for (int i = 0; i < n; i++)
            scanf("%lf", &g[i].b);
        double l = 0, h = 1;
        for (int i = 0; i < 100; i++)
        {
            double mid = (l + h) / 2.0;
            if (C(mid)) l = mid;
            else h = mid;
        }
        printf("%.f
", l*100);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Egoist-/p/7401784.html