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

Приложение 2. Задача определения глубины

Дана последовательность операций двух типов: связать(v, r) и НАЙТИ_ГЛУБИНУ(v). Начнемся неориентированных корневых деревьев, каждое из которых состоит из единственного узла i, 1  i n. Операция связать(v, r), где r корень дерева, а v – узел другого дерева, делает корень r сыном узла v. Условия о том, что v и r принадлежат различным деревьям и что r корень, гарантируют, что получаемый в результате граф также будет лесом. Операция НАЙТИ_глубину(v) состоит в том, чтобы найти и напечатать глубину узла v в текущий момент.

Если при работе с лесом использовать обычное представление в виде списков смежностей и вычислять глубину узлов очевидным образом, то сложность алгоритма будет O(п2). Вместо этого мы представим исходный лес другим лесом, который будем называть D-лесом. Он нужен нам только для того, чтобы можно было быстро вычислять глубины. Каждому узлу в D-лесу приписывается целочисленный вес так, чтобы сумма весов вдоль пути в D-лесу от узла и к корню равнялась глубине узла v в исходном лесу. Для каждого дерева в D-лесу хранится счетчик числа узлов в этом дереве.

Вначале D-лес состоит из п деревьев, каждое из которых содержит единственный узел, соответствующий целому числу i, 1  i n. Начальный вес каждого узла равен нулю.

Для выполнения операции НАЙТИ_глубину(v) мы проходим путь из узла v в корень r. Пусть v1, v2, . . ., vk узлы на этом пути (v1 = v, vk = r). Тогда

Кроме того, применяем сжатие путей. Каждый узел vi 1 i k2, делается сыном корня r. Чтобы сохранялось сформулированное выше свойство весов, новый ВЕС узла vi должен равняться для 1 i k. Так как новые веса можно вычислить за время O(k), то операция НАЙТИ_ГЛУБИНУ имеет ту же временную сложность, что и операция НАЙТИ.

Чтобы выполнить операцию связать(v, r), соединим деревья, содержащие узлы v и r, снова вливая меньшее дерево в большее. Пусть Тv и Тr деревья в D-лесу, содержащие v и r соответственно, а v' и r' – их корни. Деревья в D-лесу не обязательно изоморфны деревьям в исходном лесу, так что, в частности, r может не быть корнем для Тr. Пусть СЧЕТ(T) обозначает число узлов в дереве Т. Рассмотрим отдельно два случая.

Случай 1. СЧЕТ(Tr)  CЧЕТ(Tv). Делаем r' сыном узла v'. Мы должны также скорректировать вес старого корня r' дерева Тr так, чтобы глубина каждого узла w в Тr правильно вычислялась при прохождении пути из w в v' в объединенном дереве. Чтобы сделать это, выполняем операцию найти_глубину(v), а затем

ВЕС[г']  ВЕС[r'] – ВЕС[v'] + ГЛУБИНА(v) + 1.

Таким образом, глубина каждого узла в Тr эффективно увеличена на глубину узла v плюс 1. Наконец, полагаем счетчик числа узлов объединенного дерева равным сумме счетчиков для Тr и Тv.

Случай 2. СЧЕТ(Tv) < СЧЕТ(Tr). Здесь вычисляется ГЛУБИНА(v), преобразуется узел v' в сына узла r' и

ВЕС[r']  ВЕС [r'] + глубина(v) + 1;

BEC[v']  BEC[v'] – BEC[r'];

СЧЕТ(Тr) – СЧЕТ(Tv) + СЧЕТ(Tr).

Итак, O(п) операций СВЯЗАТЬ и НАЙТИ_ГЛУБИНУ можно выполнить за время O(nG(n)).

Приложение 3. Эквивалентность конечных автоматов

Детерминированным конечным автоматом называется машина, распознающая цепочки символов. Она имеет входную ленту, разбитую на клетки, головку на входной ленте (входную головку) и управляющее устройство с конечным числом состояний (рис. 3.24). Конечный автомат М можно представить в виде пятерки (S, I, , so, F), где

1) S – множество состояний управляющего устройства,

2) Iвходной алфавит (каждая клетка входной ленты содержит символ из I),

3)  – отображение из S x I в S (если (s, a) = s то всякий раз, когда М находится в состоянии s, а входная головка обозревает символ а, М сдвигает входную головку вправо и переходит в состояние s'),

4) sо – выделенное состояние в S, называемое начальным,

5) F подмножество в S, называемое множеством допускающих (или заключительных) состояний.

Пусть I* – множество цепочек (слов) конечной длины, состоящих из символов алфавита I. В I* включается и пустая цепочка . Продолжим  до отображения из S x I* в S:

1) (s, ) = s,

2) (s, ха) = ((s, x), а) для всех хI* и а I.

Входная цепочка х допускается автоматом М, если (sо, х)  F. Языком L(M), допускаемым автоматом М, называется множество всех цепочек, допускаемых М. Более подробное введение в теорию конечных автоматов изложено в разд. 9.1.

Два состояния s1 и s2 считаются эквивалентными, если для каждого хI* состояние (s1, х) будет допускающим тогда и только тогда, когда (s2, х) допускающее состояние.

Два конечных автомата M1 и М2 считаются эквивалентными, если L(M1)=L(М2). Мы покажем здесь, что с помощью алгоритма ОБЪЕДИНИТЬ – НАЙТИ можно распознать эквивалентность двух конечных автоматов M1 = (S1, I, 1, s1, F1) и M2=(S2, I,2, s2 F2) за O(nG(n)) шагов, где n = ||S1|| + ||S2||.

Отношение эквивалентности двух состояний обладает важным свойством: если два состояния s и s' эквивалентны, то для всех входных символов а состояния (s, а) и (s, а) также эквивалентны. Кроме того, благодаря наличию пустой цепочки, никакое допускающее состояние не может оказаться эквивалентным недопускающему. Таким образом, если допустить, что начальные состояния s1 и s2 автоматов М1 и М2 эквивалентны, то можно вывести другие пары эквивалентных состояний. Если в одну из таких пар попадет допускающее состояние вместе с недопускающим, то s1 и s2 были неэквивалентными. Если же это не произойдет, то верно обратное

begin

СПИСОК(s1, s2);

НАБОР;

for sS1  S2 do добавить {s} в НАБОР;

comment Мы только что образовали исходные множества для каждого состояния из S1  S2;

while есть пара (s, s'), входящая в СПИСОК do

begin

удалить (s, s') из множества СПИСОК; –

пусть A и A' обозначают НАЙТИ (s) и НАЙТИ (s') соответственно;

if A  A' then

begin

ОБЪЕДИНИТЬ (A, A', A);

for a I do

добавить ((s, a), (s', а)) в СПИСОК

end

end

end

Рис. 3.25. Алгоритм для нахождения множеств эквивалентных состояний в предположении, что s1 и s2 эквивалентны.

Чтобы узнать, эквивалентны ли два конечных автомата М1 = (s1, I, 1, s1, F1) и М2 = (s2, I, 2, s2, F2), мы поступаем так:

1. С помощью программы на рис. 3.25 находим все множества состояний, которые должны быть эквивалентными, если эквивалентны s1 и s2. СПИСОК содержит такие пары состояний (s, s'), что s и s' оказались эквивалентными, а следующие за ними состояния ((s, a), (s, a) еще не рассматривались. Вначале СПИСОК содержит только пару (s1, s2). Чтобы найти множества эквивалентных состояний, программа применяет алгоритм объединения непересекающихся множеств. НАБОР представляет некоторое семейство множеств. Вначале каждое состояние из S1S2 образует одноэлементное множество. (Без потери общности можно считать, что множества S1 и S2 не пересекаются.) Затем всякий раз, когда s и s' оказываются эквивалентными, содержащие их множества A и A', входящие в НАБОР, сливаются, и новое множество получает имя А.

2. После выполнения этой программы множества, входящие в НАБОР, представляют разбиение множества S1S2 на блоки состояний, которые должны быть эквивалентными. М1 и М2 эквивалентны тогда и только тогда, когда никакой блок не содержит допускающего состояния вместе с недопускающим.

Время работы этого алгоритма (как функция от числа состояний n = ||S1|| + ||S2|| определяется в основном работой алгоритма объединения множеств. Операций ОБЪЕДИНИТЬ может быть не более п–1, поскольку каждая такая операция уменьшает на единицу число множеств, входящих в НАБОР, а вначале было только п множеств. Число операций НАЙТИ пропорционально числу пар, помещенных в СПИСОК. Это число не больше n||I||, так как всякая пара, кроме начальной (s1, s2), попадает в СПИСОК только после операции ОБЪЕДИНИТЬ. Таким образом, при постоянном размере входного алфавита на распознавание эквивалентности конечных автоматов М1 и М2 тратится время O(nG (n)).