Бинарный (двоичный) поиск по ответу
Существует класс задач, в которых мы можем быстро проверять является ли какое-либо значение ответом к задаче или нет. Но сам ответ быстро найти не можем. При этом, мы можем сказать, что ответ всегда лежит в определенных границах. Кроме этого, если перебирать значения линейным перебором (от минимально возможного до максимального возможного) и проверять подходит ли нам это значение в качестве ответа, то мы будем получать такие ответы: нет нет ... нет да да ... да
(или наоборот, сначала да, потом нет).
В этом случае, мы можем для поиска ответа использовать двоичный поиск.
Основная идея решения задачи методом двоичного поиска заключается в том, чтобы сформулировать задачу "найдите максимальное (минимальное) X
, такое что какое-то свойство от X
выполняется" и решить её, подбирая значение X
бинпоиском.
Обычно, для нахождения ответа методом двоичного поиска, создают отдельную функцию, которая проверяет может ли являться переданное значение ответом или нет и возращает
True
или
False
.
Сам двоичный поиск будет выглядеть следующим образом (приведем 2 варианта реализации, которых достаточно для решения любой задачи).
// Функция check() возвращает
// сначала True, потом False
// Необходимо найти
// последний check() == True
l = 0;
r = ??? // определяется из условия
while (l + 1 < r)
{
m = (l + r) / 2;
if (check(m))
l = m;
else
r = m;
}
if (check(r))
ans = r;
elif (check(l))
ans = l;
else
ans = -1; // решения нет
|
// Функция check() возвращает
// сначала False, потом True
// Необходимо найти
// первый check() == True
l = 0
r = ??? // определяется из условия
while (l + 1 < r)
{
m = (l + r) / 2;
if (not check(m))
l = m;
else
r = m;
}
if (check(l))
ans = l;
elif (check(r))
ans = r;
else
ans = -1; // решения нет
|
Значения границ (
l
и
r
) выбираются таким образом, что при значении
l
точно не подходит (не является решением), значение
r точно подходит, хоть это значение и не является оптимальным.