二分查找答案應用十分廣泛,下面以三個例題為例
先來講講二分查找答案
總所周知,二分法查找一個數的時間複雜度為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;
}