Как сделать бинарный поиск в одной модели лжи?

вопрос такой: существует отсортированный список из n чисел. В случае x найдите число, равное x в отсортированном списке. Здесь мы предполагаем, что x действительно входит в список. Существует оракул, который может ответить "да" или "нет" на ваш вопрос "есть ли x >= y?". В отличие от обычного бинарного поиска, оракулу разрешается лежать один раз на ваш вопрос. Самый наивный способ решить эту проблему - вы дважды задаете каждый вопрос оракулу. Если два ответа одинаковы, вы знаете, что орал не лжет. Этот алгоритм нам нужно сравнить 2log_2 (n) раз. Но этот вопрос попросит меня найти алгоритм, который может найти x, используя только сравнения log_2 (n) + o (logn).

Я очень старался, но не смог. Может ли кто-нибудь дать мне несколько советов о том, как решить эту проблему? Спасибо.

Ответ 1

Следите за интервалом, в котором вы находитесь. Если вам требуется в общей сложности k вопросы, проверьте последовательность (независимо от того, находитесь ли вы в том промежутке, который вы должны быть), каждый шаг sqrt(k). Проверяя последовательность, вы можете задать каждый вопрос дважды, чтобы быть уверенным. Если вы обнаружите несогласованность, вернитесь назад sqrt(k). Вы будете задавать не более чем c*sqrt(k) дополнительные вопросы.

Ответ 2

Используйте тот факт, что после того, как оракул соврал, двоичный поиск идет неправильным образом, и вы не получаете никаких изменений в ответе оракула с этого времени (всегда >= или всегда <). Если вы не получили изменений в ответе оракула для шагов log(log(n)), проверьте соответствие интервалов. Если текущий интервал несовместим, попросите оракул еще раз, и если все еще несовместимы, вернитесь назад log(log(n)) + 1 и продолжайте с обычным двоичным поиском.

Эта процедура требует O(log(log(n))) проверки согласованности в среднем и до log(log(n)) дополнительных шагов бинарного поиска.

Среднее количество дополнительных вопросов c*log(log(n)), максимальное количество дополнительных вопросов - log(n) / (log(log(n))) + log(log(n)).

Ответ 3

Спросите у оракула вопрос: "is x >= y?" один раз на каждой итерации вашего бинарного поиска. Если вы получите один и тот же ответ дважды, то вы знаете, что оракул не первый раз лежал.

Например, вы ищете x = 1 и первый тест, который вы тестируете против y = a, а oracle отвечает x < а. На втором тесте вы проверите против y = b, и оракул отвечает x < б. Поскольку вы используете двоичный поиск, и оракул сказал '<', и массив отсортирован, вы знаете, что b < а. Следовательно, если x < b, вы также знаете, что x < а, и первый ответ не был ложью. Если второй ответ - ложь и x > b, то все же верно, что x < а, поскольку оракул может лежать только один раз.

Это верно, даже если ответы не возвращаются назад. Например, вы получаете три ответа: x < a, x >= b, x < c, вы знаете, что c < a, вашим двоичным поиском, и поэтому должно быть верно, что x < а, и оракул не лгал, когда он сказал вам это.

Итак, что происходит, когда оракул говорит ложь? Если бы ложь была х < y, то истина была x >= y. Поэтому, когда вы продолжаете свой двоичный поиск, с этой точки, числа, которые вы проверяете, будут слишком малы, и ответ всегда будет " > =", пока вы не достигнете дна бинарного поиска. В этот момент вы понимаете, что если оракул лгал, он лгал в последний раз, когда он говорил вам что-то другое, кроме " > =". Поэтому вы перезапускаете свой двоичный поиск в точке, где оракул лгал вам, и сказал "x < y".

Это всегда будет использовать < 2 log_2 n, но если оракул принадлежит вам в начале поиска, вам придется повторить почти log_2 n работу, и поэтому вы не получите ответ log_2 n + o (log n), который вы искали, Таким образом, вы должны включить идею, предложенную nm. Если вы получите тот же ответ, скажите sqrt (log n) раз подряд, то вы подозреваете, что оракул, возможно, лгал вам, и вы сразу же задаете вопрос, спросил, прежде чем ответы начали повторяться, вместо того, чтобы ждать дна бинарного поиска. Следуя этой стратегии, вы будете повторно запрашивать журнал вопросов n/sqrt (log n) раз в худшем случае, и вы всегда будете ловить ложь с максимальной нагрузкой sqrt (log n), которая достигает времени выполнения, которое вы были находясь в поиске.

Ответ 4

Я думаю, что решение этого вопроса в 3 * log(n) может быть простым, задавая вопрос о неравенстве три раза на каждом шаге, и решение является большинством.

Ответ 5

Вы можете захотеть изменить классический бинарный поиск, чтобы это работало, как попросить попросить оракула на каждой итерации сравнить 2 разных индекса массива вместо 1, что-то вроде:

assume Oracle(x,y) returns "x>=y?", assume every division is returning floor integer.
LyingOracleSearch(A,n,toFind)
1. if (n==0) return not found
2. if (A[0]==toFind) return found
3. if (Oracle(A[n/4],toFind) and Oracle(toFind,A[3n/4]) then
4.                      return LyingOracleSearch(A[(n/4)...(3n/4)],3n/4-n/4,toFind)
5. if (Oracle(A[n/4],toFind) and !Oracle(toFind,A[3n/4]) then
6.                      return LyingOracleSearch(A[0...(n/4)],n/4,toFind)
7. if (!Oracle(A[n/4],toFind) and Oracle(toFind,A[3n/4]) then
8.                      return LyingOracleSearch(A[(3n/4)...n],n-3n/4,toFind)
9. return LyingOracleSearch(A,n,toFind);  \\orcale lied!

Я думаю, что это гвоздь, возможно, неправильно.

сложность такая же, как у исходной BS, но лучше спросить оракула дважды или более. обратите внимание, что элемент никогда не сравнится по сравнению с дважды, если оракул не лежит, поэтому, если он лежит один или даже k раз, когда k мало-о (logn), тогда мы в порядке.

вы можете пойти в свою любимую среду кодирования и попытаться ее кодировать, каждый раз, когда делается сравнение, считайте это. попробуйте как этот, так и наивный, и сравните результат, если он не ошибается, наивный должен сравнить в два раза больше, чем это.

Обратите внимание, что я не был слишком осторожен с индексами, вам нужно будет подумать, чтобы убедиться, что я не пропустил индекс или не повторял индекс случайно.