Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конец главы 3.doc
Скачиваний:
13
Добавлен:
05.11.2018
Размер:
926.21 Кб
Скачать

3.13. Разбиение

Рассмотрим специальный тип расцепления, называемый разбиением. Задача разбиения множества возникает довольно часто, и решение, которое мы продемонстрируем здесь, поучительно само по себе. Пусть даны множество S и разбиение  множества S на непересекающиеся блоки {B1, B2, . . ., Вр}. Кроме того, дана функция f, отображающая S на S.

Наша задача состоит в том, чтобы найти такое грубейшее (с наименьшим числом блоков) разбиение, ' = {E1, Е2, . . ., Еq} множества S, что

1) ' – подразбиение разбиения  (т. е. каждое множество Ei -является подмножеством некоторого блока Bj),

2) если а и b принадлежат Ei то f (а) и f(b) принадлежат Ej для некоторого j.

Будем называть ' грубейшим разбиением множества S, совместимым с и f.

Очевидное решение состоит в повторном утончении блоков исходного разбиения следующим способом. Пусть Bi какой-нибудь блок. Рассмотрим f(a) для каждого а из Bi. Разобьем Вi так, чтобы два элемента а и b попадали в один блок тогда и только тогда, когда f(a) и f(b) оба принадлежат некоторому блоку Bj. Процесс повторяется до тех пор, пока уже нельзя будет проводить дальнейшие утончения. Этот метод дает алгоритм сложности O(п2), поскольку каждое утончение занимает время O(n), а всего может быть O(п) утончений. Пример 3.13 показывает, что действительно может потребоваться квадратичное число шагов.

Пример 3.13. Пусть S = {1, 2, . . ., п} и B1 ={l, 2, . . ., п - 1}, B2={n}–исходное разбиение. Пусть f – такая функция на S, что f(i) = i + 1 для 1  i п и f(n) = n. При первой итерации B1 разбиваем на {1, 2, . . ., n – 2} и {п1}. Эта итерация занимает п1 шагов, поскольку надо просмотреть каждый элемент в B1. При следующей итерации разбиваем {1, 2, . . ., п2} на {1, 2, ... .... п3} и {п2}. Продолжая в том же духе, выполняем всего п2 итерации, причем i-я итерация занимает пi шагов. Следовательно, всего требуется

шагов. Окончательным разбиением будет Еi = {i} для 1  i n.

Недостаток этого метода состоит в том, что утончение блока может потребовать O(п) шагов, даже если из него удаляется только один элемент. Сейчас мы опишем алгоритм разбиения, который для разделения блока на два подблока требует время, пропорциональное размеру меньшего подблока. Этот подход приводит к алгоритму сложности O(п log п).

Для каждого блока BS положим f-1 (В)= {bf(b) В}. Вместо того чтобы разбивать Вi по значениям f(a) для аBi, разобьем относительно Вi те блоки Bj, которые содержат хотя бы один элемент из f-1 (Вi) и один элемент не из f-1 (Bi). Иными словами, каждый такой блок Bj разбивается на множества {bb Вj и f(b) Вi}. и {bb Вj и f(b)Bi}.

Как только проведено разбиение относительно блока Вi, больше уже не нужно проводить разбиения относительно него, пока он сам не будет расщеплен. Если вначале f(b)Bi для каждого элемента bBj и Bi расщеплен на Вi и Вi, то можно разбить Bj относительно Вi или Вi, и получить при этом один и тот же результат, поскольку {bbBj и f(b)Bi} совпадает с bj -{bbBj и f(b)Bi}.

Так как можно выбирать, по отношению к какому из блоков Вi или Вi, проводить разбиение, то мы разбиваем относительно того, для которого это сделать проще. Точнее мы выбираем меньшее из множеств f-1(Bi) и f-1 (Bi"). Алгоритм приведен на рис. 3.35.

Алгоритм 3.5. Разбиение

Вход. Множество S из п элементов, разбиение  = {B[1], . . . . . ., В[р]} и функция f: SS.

Выход. Грубейшее разбиение  ={В[1], В[2], . . ., B[q]} множества S, совместимое c  и f.

begin

1. ОЖИДАНИЕ {1, 2, ..., р};

2. q  р;

  1. white ОЖИДАНИЕ не пусто do

begin

4. выбрать и удалить любое целое число i из множества ОЖИДАНИЕ;

5. ОБРАЩЕНИЕ  f-1(B [i])

  1. for j, для которых B[j]ОБРАЩЕНИЕ  и В[j]  ОБРАЩЕНИЕ do

begin

7. qq+1

8. создать новый блок B[q]

9. В [q] В[j]ОБРАЩЕНИЕ;

10. B[j]B[j]-B[q]

11. if j  ОЖИДАНИЕ then

добавить q в ОЖИДАНИЕ

else

12. if ||В[j]||  ||В[q] || then

13. добавить j в ОЖИДАНИЕ

14. else добавить q в ОЖИДАНИЕ

end

end

end

Рис. 3.35. Алгоритм разбиения.

Метод. К  применяется программа, приведенная на рис. 3.35. В ней опущены некоторые детали, важные для ее реализации. Мы обсудим эти детали при анализе времени работы алгоритма. 

Анализ алгоритма 3.5 начнем с доказательства того, что он разбивает S нужным образом. Пусть – разбиение множества S и f – отображение множества S на себя. Множество TS будем называть безопасным для , если для любого блока В либо B f-1(T), либо В f-1 (T) = . Например, на рис. 3.35 строки 9 и 10 гарантируют, что множество B[i] безопасно для получающегося разбиения, поскольку если Вf-1 (B[i])   для некоторого блока B, то либо В ОБРАЩЕНИЕ и тогда включение Bf-1(B[i]) очевидно, либо в строках 9 и 10 B разбивается на два блока, один из которых является подмножеством множества f-1(B[i]), а другой с ним не пересекается.

В доказательство корректности алгоритма 3.5 входит доказательство того, что окончательное разбиение не оказывается слишком грубым. Иными словами, надо доказать следующее.

Лемма 3.7. После окончания работы алгоритма 3.5 каждый блок В в результирующем разбиении ' безопасен для '.

Доказательство. На самом деле мы покажем, что для каждого блока В[l].

п

3.6

осле каждого выполнения цикла в строках 4–14 на рис. 3.35, если lОЖИДАНИЕ и l q, формируется такой список q1, q2, ...,qk (возможно, пустой), что qi  ОЖИДАНИЕ, 1 i k, и множество B[l]B[q1]...B[qk] безопасно для разбиения, построенного в данный момент.

Интуитивно это можно изложить так: когда число l удаляется из множества ОЖИДАНИЕ, строки 6–14 делают блок В[l] безопасным для разбиения, которое получается после строки 14. В[l] остается безопасным до тех пор, пока он не будет разбит. Когда В[l] разбивается, индекс одного подблока, назовем его B[q], помещается в ОЖИДАНИЕ. Другой подблок по-прежнему называется В[l]. Очевидно, что объединение этих двух подблоков, т. е. B[l]B[q], безопасно для рассматриваемого разбиения, поскольку оно совпадает со старым блоком В[l]. Дальнейшее разбиение образует такие блоки B[q1], . . ., B[qk], что q1, . . ., qk входят в ОЖИДАНИЕ, а объединение R=B[l]B[q1] . . .B[qk] безопасно. Когда qi при некотором i(1 i k) удаляется из множества ОЖИДАНИЕ, строки 6–14 снова делают B[qi] и R B[qi] безопасными. Изложим теперь это формально. Докажем справедливость утверждения (3.6) для всех l индукцией по числу выполнении строк 4–14. Когда алгоритм заканчивает работу, множество ОЖИДАНИЕ пусто, и, значит, из (3.6) будет вытекать, что каждый блок окончательного разбиения ' безопасен для '.

Для доказательства базиса возьмем 0 выполнении, тогда (3.6) тривиально, поскольку lОЖИДАНИЕ для всех 1 l q=p.

Для проведения шага индукции предположим, что после выполнения строки 14 lОЖИДАНИЕ. Если число l всегда ранее входило в ОЖИДАНИЕ, то оно имеет значение i, которое определялось в строке 4. Легко показать, что цикл в строках 6–14 делает B[i] безопасным для разбиения, получающегося после выполнения строки 14. Это мы уже обосновали после определения понятия "безопасный".

Если число l не входило в ОЖИДАНИЕ во время предыдущегo выполнения цикла до строки 14, то по предположению индукции найдется такой список q1, q2., . ., qk, что (3.6) было справедливо для l на предыдущем этапе. Кроме того, в строке 4 обязательно i l.

Случай 1. i нет в L={ q1, q2., . ., qk }. В строках 9, 10 могло произойти разбиение нескольких блоков. Для каждого такого блока B[qr] 1' r k (т. е. j = qr) добавим в L индекс блока, образованного в строке 8. Благодаря строке 11 список L по-прежнему будет состоять только из индексов, входящих в ОЖИДАНИЕ. Если сам блок В[l] не разбит, то В[l] и множество блоков с индексами из L все еще образуют множество, безопасное для текущего разбиения, так что (3.6) удовлетворяется. Если же блок В [l] разбит, надо также добавить в L индекс q, выбранный в строке 8, когда j=l. Следовательно, множество B[l] будет безопасно для текущего разбиения.

Случай 2. i находится в L={ q1, q2., . ., qk }. Без потери общности будем считать, что i=q1. Рассуждение проводится почти так же, как в случае 1, но q1 в конце рассматриваемой итерации строк 4–14 может не входить в ОЖИДАНИЕ. Мы знаем, что каждый блок В текущего разбиения будет либо подмножеством множества f-1(B[q1]), либо не будет с ним пересекаться. Пусть Т=В[l] , где список L модифицирован, как в случае 1.

Если B f-1(B[q1]), то, разумеется, Bf-1(T)=. Если B f-1(B[q1]) = , то аналогично случаю 1 можно доказать, что В f-1(T)= или В f-1(T)=.

Наконец, когда алгоритм 3.5 заканчивает работу, множество ОЖИДАНИЕ должно быть пусто. Следовательно, из (3.6) вытекает, что для каждого l блок В[l] безопасен для окончательного разбиения. 

Теорема 3.8. Алгоритм 3.5 правильно вычисляет грубейшее разбиение множества S, совместимое с и f.

Доказательство. Лемма 3.7 показывает, что выход ' алгоритма 3.5 совместим c  и f. Надо доказать, что разбиение ' грубо, насколько возможно. Простая индукция по числу блоков, разбиваемых в строках 9, 10, показывает, что каждое такое разбиение, сделанное алгоритмом, необходимо для совместимости. Оставляем эту индукцию в качестве упражнения. 

Теперь мы должны детально исследовать реализацию алгоритма 3.5, чтобы показать, что время его работы составляет O(п log n), где n = ||S||. Основным при оценке времени работы будет демонстрация того, что цикл в строках 6–14 можно выполнить за время, пропорциональное ||ОБРАЩЕНИЕ||. Наша первая задача – эффективно найти подходящее множество чисел j в строке 6. Нам понадобится такой массив БЛОК, что БЛОК[l] – индекс блока, содержащего l. Начальное состояние массива БЛОК можно построить за O(п) шагов, после строки 9 скорректировать его за время, не большее того, что тратится на формирование списка B[q] в этой строке. Следовательно, поскольку нас интересует только порядок временной сложности, можно не учитывать время, затрачиваемое на работу с массивом БЛОК.

С помощью массива БЛОК легко построить список JСПИСОК чисел j, необходимых в строке 6, за O(||ОБРАЩЕНИЕ||) шагов. Для каждого элемента а, входящего в ОБРАЩЕНИЕ, индекс блока, содержащего а, добавляем в JCПИCOK, если его там еще нет. Для каждого j хранится счетчик числа элементов, входящих в ОБРАЩЕНИЕ, которые входят также и в B[j]. Если этот счетчик достигнет величины ||B[j]||, то B[j] ОБРАЩЕНИЕ и j удаляется из списка JCПИCOK.

Используя БЛОК, можно для каждого j, входящего в JCПИCOK, построить также список ПЕРЕСЕЧЕНИЕ[j], в который войдут все целые числа, принадлежащие обоим множествам B[j] и ОБРАЩЕНИЕ. Чтобы быстро удалить элементы списка ПЕРЕСЕЧЕНИЕ[j] из B[j] и добавить их в B[q], надо поддерживать списки В[l], 1 l q, в дважды связанном виде, т. е. с указателями как к следующей, так и к предыдущей компонентам.

Строки 9 и 10 требуют O(||B[q]||) шагов. Для данного выполнения for-цикла суммарное время, затрачиваемое на нахождение подходящих чисел j и на выполнение строк 7–10, составляет О(||ОБРАЩЕНИЕ||). Кроме того, легко видеть, что тест в строках 12–14, если его выполнять должным образом, занимает O(||B[q]||) времени, так что общее время есть O(||ОБРАЩЕНИЕ||).

Осталось рассмотреть строку 11. Чтобы быстро сказать, входит ли j в ОЖИДАНИЕ, образуем другой массив В_ОЖИДАНИИ[j]. Начальное состояние В_ОЖИДАНИИ можно построить за O(n) шагов и без труда корректировать его в строках 11–14. Таким образом, мы доказали следующую лемму.

Лемма 3.8. for-цикл в строках 6–14 на рис. 3.35 можно реализовать за О(||ОБРАЩЕНИЕ||) шагов.

Доказательство. В силу изложенного выше. 

Теорема 3.9. Алгоритм 3.5 можно реализовать за время O(п log n).

Доказательство. Рассмотрим условия, при которых блок, содержащий целое число s и не представленный в множестве ОЖИДАНИЕ, может попасть туда. В строке 1 это может случиться лишь один раз. В строке 11 это произойти не может, даже если sB[q], поскольку тогда s было бы в B[j] еще раньше, а индекс j уже входил в ОЖИДАНИЕ. Если это случилось в строках 13 и 14, то число s находится в блоке, размер которого не больше половины размера того блока, куда оно входило в тот предыдущий момент, когда индекс множества, содержащего s, попал в ОЖИДАНИЕ. Отсюда можно заключить, что индекс множества, содержащего s, попадает в ОЖИДАНИЕ не больше 1+ log n раз. Следовательно, s не может быть в блоке i, который выбирался в строке 4 более чем 1+ log n раз.

Допустим, что на каждый элемент s из B[i] каждый раз налагается штраф, пропорциональный ||f-1 (s)||, так что сумма всех штрафов равна сложности выполнения цикла в строках 6–14. Тогда существует такая постоянная с, что за одно выполнение цикла элемент s штрафуется не более чем на c||f-1 (s)||. Как мы уже показали, элемент s не может попасть в выбираемый список B[i] более чем O(log n) раз, так что суммарный штраф, налагаемый на него, составляет O(||f-1 (s)|| log n). Так как сумма

должна равняться n, то общая сложность всех выполнении for-цикла есть O(п log n). Легко видеть, что сложность остальной части алгоритма 3.5 есть O(); теорема доказана. 

Алгоритм 3.5 имеет несколько приложений. Одно из важных приложений – минимизация числа состояний конечного автомата. Дан конечный автомат M=(S, I, , so, F) и требуется найти эквивалентный ему автомат М' с наименьшим числом состояний. Для каждого состояния s и входного символа а обозначим через (s, а) очередное состояние автомата. Вначале все состояния автомата М можно разбить на множество F допускающих состояний и множество S – F недопускающих состояний. Задача минимизации числа состояний автомата М эквивалентна нахождению грубейшего разбиения ' множества S, совместимого с начальным разбиением {F, S – F} и такого, что если состояния s и t находятся в одном блоке разбиения ', то состояния (s, а) и (t, а) также находятся в одном блоке автомата М' для каждого входного символа а.

Единственное отличие этой задачи от задачи, решаемой алгоритмом 3.5, состоит в том, что – отображение из Sx1 в S, а не из S в S. Однако можно трактовать как множество {a1, a2, . . . . . ., am} функций на S, где a – сужение функции на а.

Алгоритм 3.5 легко модифицировать так, что он справится с этой более общей задачей, помещая в множество ОЖИДАНИЕ пары (i, a). Каждая пара (i, a) состоит из индекса i некоторого блока разбиения и функции a, по которой проводится разбиение. Вначале ОЖИДАНИЕ ={( i, a )|i = 1 или 2 и a 1}, поскольку начальное разбиение {F, S – F} состоит из двух блоков. Всякий раз, когда блок В[j] разбивается на В[j] и B[q], каждая допустимая функция a спаривается с j и q. Остальные детали оставляем в качестве упражнения.

1 Таким образом, «единица времени» здесь занимает некоторое постоянное число шагов на РАМ. Так как мы пренебрегаем постоянными множителями, то результаты о порядке величины можно также выражать через «единицы времени».

1 По поводу сложности задачи, рассматриваемой в данном разделе, см. работу Тарьяна [1977].– Прим. пepeв.

1 E[v] – элемент, приписанный узлу v.

1 Достаточно пройти путь от а до такого узла, что а не наибольший элемент в fro поддереве.

1 Два узла с одним отцом называются братьями.

1 Если нам нужны значения L и М для нового узла, образованного процедурой ДОБДВСЫНА(f), то сначала надо найти наибольшего потомка узла с, следуя по пути, идущему в самый правый лист.

1 Здесь различие между «левым» и «правым» неважно; оно сделано ради сцепляемых очередей, которые обсуждаются в следующем разделе.

1 Результат процедуры ИМПЛАНТАЦИЯ(Т', Т') отнести к левому лесу. Аналогично при применении к деревьям из правого леса результат процедуры ИМПЛАНТАЦИЯ относится к правому лесу.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]