二分的几种简单应用——入门
---恢复内容开始---
说起二分,最基础的二分搜索算法就不用了吧(最难的还际应用啊感觉)……实现起来很简单,搜索区间不断减半……唔……嘛……简单甩个模板好了(●'◡'●)
下面开始学习二分的几种应用啦~~
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
Output
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\n", 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
* Lines 2..N+1: Line i+1 contains an integer stall location, xi
Output
Sample Input
5 3 1 2 8 4 9
Sample Output
3
Hint
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.
#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\n", 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 ≤ k ≤ n ≤ 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了再贴代码
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
.
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.
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.
3 1 5 0 2 5 1 6 4 2 1 2 7 9 5 6 7 9 0 0Sample Output
83 100Hint
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\n", l*100); } return 0; }