Разминка: случайные битовые векторы
В качестве разминки мы можем начать со случая, когда каждый битовый вектор выбирается равномерно случайным образом. Тогда оказывается, что проблема может быть решена за O(n1.6min(k,lgn)) времени (точнее, 1.6 можно заменить на lg3 ).
Мы рассмотрим следующий двунаправленный вариант задачи:
С учетом множества из битвекторов, определить , где существует неперекрывающийся пары сек ∈ S , T ∈ T .S,T⊆{0,1}ks∈S,t∈T
Основной метод решения этой проблемы - разделяй и властвуй. Вот алгоритм времени , использующий принцип «разделяй и властвуй»:O(n1.6k)
Разделите и T на основе первой позиции бита. Другими словами, форма S 0 = { s ∈ S : s 0 = 0 } , S 1 = { s ∈ S : s 0 = 1 } , T 0 = { t ∈ T : t 0 = 0 } , T 1 = { t ∈ T : tSTS0={s∈S:s0=0}S1={s∈S:s0=1}T0={t∈T:t0=0} .T1={t∈T:t0=1}
Теперь рекурсивно ищем неперекрывающуюся пару из , из S 0 , T 1 и из T 1 , S 0 . Если какой-либо рекурсивный вызов найдет неперекрывающуюся пару, выведите его, в противном случае выведите «Перекрывающаяся пара не существует».S0,T0S0,T1T1,S0
Поскольку все битовые векторы выбираются случайным образом, мы можем ожидать и | Т б | ≈ | T | / 2 . Таким образом, у нас есть три рекурсивных вызова, и мы уменьшили размер задачи в два раза (оба набора уменьшились в размере в два раза). После разбиения lg min ( | S | , | T | ) один из двух наборов уменьшается до размера 1, и проблема может быть решена за линейное время. Мы получаем рекуррентное соотношение в соответствии с|Sb|≈|S|/2|Tb|≈|T|/2lgmin(|S|,|T|) , чье решение T ( n ) = O ( n 1.6 k ) . Учет времени работы более точно в случае с двумя наборами, мы видим, что время работы составляет O ( мин ( | S | , | T | ) 0,6 макс ( | S | , | TT(n)=3T(n/2)+O(nk)T(n)=O(n1.6k) .O(min(|S|,|T|)0.6max(|S|,|T|)k)
Это можно еще улучшить, отметив, что если , то вероятность того, что непересекающаяся пара существует, экспоненциально мала. В частности, если х , у двух случайных векторов, вероятность того, что они не перекрывающиеся является ( 3 / 4 ) K . Если | S | = | T | = n , существует n 2 таких пар, так что по границе объединения вероятность того, что неперекрывающаяся пара существует, не превышает n 2 ( 3k≥2.5lgn+100x,y(3/4)k|S|=|T|=nn2 . Когда к ≥ 2,5 Л.Г. п + 100 , это ≤ 1 / 2 100 . Таким образом, в качестве шага предварительной обработки, если k ≥ 2,5 lg n + 100 , мы можем сразу же вернуть «Не существует непересекающейся пары» (вероятность того, что это неверно, пренебрежимо мала), в противном случае мы запускаем описанный выше алгоритм.n2(3/4)kk≥2.5lgn+100≤1/2100k≥2.5lgn+100
Таким образом, мы достигаем время работы (или O ( мин ( | S | , | T | ) 0,6 макс ( | S | , | T | ) min ( k , lg n) ) ) для предложенного выше варианта с двумя наборами), для частного случая, когда битовые векторы выбираются случайным образом равномерно.O(n1.6min(k,lgn))O(min(|S|,|T|)0.6max(|S|,|T|)min(k,lgn))
Конечно, это не худший анализ. Случайные битовые векторы значительно проще, чем в худшем случае, но давайте рассмотрим это как разминку, чтобы получить некоторые идеи, которые, возможно, мы сможем применить к общему случаю.
Уроки разминки
Мы можем выучить несколько уроков из разминки выше. Во-первых, «разделяй и властвуй» (разделяя на битовую позицию) кажется полезным. Во- вторых, вы хотите разделить на позицию бита с таким количеством «S в таком положении , как это возможно; чем больше 0 , тем меньше уменьшение размера подзадачи.10
В- третьих, это говорит о том, что эта проблема становится все труднее , как плотность «S становится все меньше - если есть очень мало 1 » S среди битвекторов (они в основном 0 «s), проблема выглядит довольно сложно, так как каждый раскол уменьшает размер подзадач немного. Итак, определите плотность Δ, чтобы быть долей битов, которые равны 1 (то есть из всех n k битов), и плотность позиции бита i, чтобы быть долей векторов битов, которые равны 1 в позиции i .110Δ1nki1i
Обработка очень низкой плотности
В качестве следующего шага мы могли бы задаться вопросом, что произойдет, если плотность чрезвычайно мала. Оказывается, что если плотность в каждой позиции бита меньше , мы гарантируем, что существует неперекрывающаяся пара: существует (неконструктивный) аргумент существования, показывающий, что некоторая непересекающаяся пара должна существовать. Это не помогает нам найти его, но, по крайней мере, мы знаем, что оно существует.1/k−−√
Почему это так? Скажем , что пара битвекторов будет покрыта на битовой позиции я , если х я = у я = 1 . Обратите внимание, что каждая пара перекрывающихся битовых векторов должна быть покрыта некоторой битовой позицией. Теперь, если мы фиксируем конкретную битовую позицию i , количество пар, которые могут быть покрыты этой битовой позицией, составляет самое большее ( n Δ ( i ) ) 2 < n 2 / k . Суммирование по всем kx,yixi=yi=1i(nΔ(i))2<n2/kkиз битовых позиций мы находим, что общее количество пар, которые покрыты некоторой битовой позицией, составляет . Это означает, что должна существовать некоторая пара, которая не покрыта какой-либо битовой позицией, что означает, что эта пара не перекрывается. Таким образом, если плотность достаточно низкая в каждой позиции бита, то непересекающаяся пара наверняка существует.<n2
Однако я затрудняюсь определить быстрый алгоритм для нахождения такой неперекрывающейся пары в этих режимах, хотя гарантированно существует такая. Я не сразу вижу какие-либо методы, которые дали бы время выполнения, которое имеет субквадратичную зависимость от . Итак, это хороший особый случай, на котором стоит сосредоточиться, если вы хотите потратить некоторое время на обдумывание этой проблемы.n
На пути к общему алгоритму
В общем случае естественная эвристика выглядит так: выберите битовую позицию с наибольшим числом 1 (т. Е. С наибольшей плотностью) и разделите ее. Другими словами:i1
Найдите положение бита которое максимизирует Δ ( i ) .iΔ(i)
Разделить и T на основе положения бита i . Другими словами, форма S 0 = { s ∈ S : s i = 0 } , S 1 = { s ∈ S : s i = 1 } , T 0 = { t ∈ T : t i = 0 } , T 1 = { t ∈ T :STiS0={s∈S:si=0}S1={s∈S:si=1}T0={t∈T:ti=0} .T1={t∈T:ti=1}
Теперь рекурсивно ищем неперекрывающуюся пару из , из S 0 , T 1 и из T 1 , S 0 . Если какой-либо рекурсивный вызов найдет неперекрывающуюся пару, выведите его, в противном случае выведите «Перекрывающаяся пара не существует».S0,T0S0,T1T1,S0
Задача состоит в том, чтобы проанализировать его производительность в худшем случае.
Давайте предположим, что в качестве шага предварительной обработки мы сначала вычислим плотность каждой позиции бита. Также, если для каждогоi, предположим, что на этапе предварительной обработки выводится «перекрывающаяся пара» (я понимаю, что это не демонстрирует пример перекрывающейся пары, но давайте отложим это как отдельную задачу). Все это можно сделать заO(nk)раз. Информация о плотности может поддерживаться эффективно, поскольку мы делаем рекурсивные вызовы; это не будет доминирующим фактором времени выполнения.Δ(i)<1/k−−√iO(nk)
Какой будет продолжительность этой процедуры? Я не уверен, но вот несколько замечаний, которые могут помочь. Каждый уровень рекурсии уменьшает размер проблемы примерно на битовых векторов (например, отnбитовых векторов доn-n/ √n/k−−√n битвекторов). Поэтому рекурсия может идти только о √n−n/k−−√ уровней глубоко. Тем не менее, я не сразу уверен, как посчитать количество листьев в дереве рекурсии (их намного меньше, чем3 √k−−√ уходит), поэтому я не уверен, к какому времени это должно привести.3k√