二分查找答案应用十分广泛,下面以三个例题为例
先来讲讲二分查找答案
总所周知,二分法查找一个数的时间复杂度为O(log n),所以在int范围内找一个数最多只需要30余次,在longlong范围内最多也只需要60余次。因此,我们可以利用二分这一优势查找答案。即,每次二分后判断该数是不是满足题目要求。
上模板代码:
const int N = 0x3f3f3f3f;
int main()
{
int ans, l, r;
int l = a, r = b;//a为上限,b为下限
while (l <= r)
{
mid = (l + r) / 2;
if (check(mid))
/*判断二分得到的mid是不是满足题目要求,
并且将二分的上限或下限相对应的缩小*/
{
ans = mid;
mid = l + 1;
}
else
mid = r - 1;
}
cout << ans << endl;
return 0;
}
下面以三道题目为例
1.吉首大学新星杯
(ps:这道题现在应该不能交了)
这道题n个整数表示樱花的高度,然后问你最小速度为多少时,所有樱花都可以在m秒内飘落完
二分代码:(由于该题评测关闭,不确定代码正确性):
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 0x3f3f3f3f;
int p[2000005];
int main()
{
ll n, m, ans;
cin >> n >> m;
for (int i = 0; i < n; i++)
scanf("%d", &p[i]);
ll l = 1, r = N, mid;
while (l <= r)
{
mid = (l + r) / 2;
ll sum = 0;
for (ll i = 0; i < n; i++)
{
sum += p[i] / mid;
if (p[i] % mid != 0)
sum++;
}
if (sum <= m)
{
ans = mid;
r = mid - 1;
}
else
l = mid + 1;
}
cout << ans << endl;
return 0;
}
2.POJ2456
Aggressive cows
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.
这题告诉你有n个隔间,然后有m头牛,一头牛住一个隔间,将m头牛分得尽可能开之后,两头牛的最小距离是多少
二分代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 0x3f3f3f3f;
int p[100005];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
scanf("%d", &p[i]);
sort(p, p + n);
ll l = 0, r = p[n - 1] - p[0], ans;
while (l <= r)
{
ll mid =(l+r)/2;
ll sum = 0;
int t = 0;
for (int i = 0; i < n; i++)
{
if (p[i] - p[t] >= mid)
{
t = i;
sum++;
}
}
if (sum + 1 >= m)
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
cout << ans << endl;
return 0;
}
3.计蒜客 存款
银行存钱问题,给你三个整数
p
,
y
,
t
。
p
:一年存钱可以获得的利息,
y
总共的年数,
t
最后获得的最少金额。问:小明最少每年投入多少钱,才能在
y
年后拥有至少
t
元。(小明每年将上一年的本金加利息一并存入银行)
坑点:上面两道题的二分答案的判断过程 即模板中的check过程都可以算完,
最后再与题目要求比较
,但是这道题会爆long long,所以我们每算一次sum就判断是不是超过最后所要拥有的金额t,如果是,那么直接跳出判断过程。
二分代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long y, t;
double p;
cin >> p >> y >> t;
long long l = 1, r = t, mid, ans;
while (l <= r)
{
int flag = 0;
mid = (l + r) / 2;
long long sum = 0;
for (long long i = 1; i <= y; i++)
{
sum = (sum + mid) * (100 + p) / 100;
if (sum >= t)
{
flag = 1;
break;
}
}
if (flag)
{
ans = mid;
r = mid - 1;
}
else
l = mid + 1;
}
cout << ans << endl;
return 0;
}