Аноним

Прямолинейное дерево Штейнера: различия между версиями

Материал из WEGA
м
нет описания правки
мНет описания правки
 
(не показано 25 промежуточных версий этого же участника)
Строка 4: Строка 4:


== Постановка задачи ==
== Постановка задачи ==
Пусть даны точки на плоскости. Минимальное дерево Штейнера (SMT) соединяет эти точки при помощи дополнительных точек, называемых точками Штейнера, так, чтобы общая сумма расстояний между ними была минимальной. Если в качестве расстояния между двумя точками берется расстояние по прямой, такое дерево называется прямолинейным минимальным деревом Штейнера.
Пусть даны точки на плоскости. Минимальное [[дерево Штейнера]] (SMT) соединяет эти точки при помощи дополнительных точек, называемых точками Штейнера, так, чтобы общая сумма расстояний между ними была минимальной. Если в качестве расстояния между двумя точками берется расстояние по прямой, такое дерево называется прямолинейным минимальным деревом Штейнера.




В силу высокой значимости этой задачи для ее решения было разработано немало алгоритмов, которые можно разбить на два класса: точные и эвристические. Поскольку задача SMT является NP-полной, любой точный алгоритм будет иметь ожидаемое экспоненциальное время исполнения в наихудшем случае. Однако в этой области были достигнуты два значительных улучшения. Одним из них стал алгоритм GeoSteiner в реализации Уорма, Уинтера и Захарисена [14, 15] – самый быстрый на данный момент точный алгоритм для решения этой задачи. Второй алгоритм, схема аппроксимации с полиномиальным временем исполнения (Polynomial Time Approximation Scheme, PTAS) Ароры [ ], имеет скорее теоретическую значимость. Поскольку время исполнения точных алгоритмов получается очень долгим, особенно для входных данных большого объема, намного больше внимания было уделено разработке эвристических алгоритмов. Многие из них генерируют дерево Штейнера посредством улучшения топологии минимального остовного дерева (MST) [ ], так как было доказано, что MST является 3/2-аппроксимацией SMT [ ]. Однако из-за того, что в этих подходах базовые структуры ограничены топологией минимального остовного дерева, степень улучшений по сравнению с ним ограничена. Итерационный алгоритм 1-Steiner Канга и Робинса [ ] был одной из первых попыток обойти это ограничение, а его улучшенная реализация [ ] стала самой популярной из подобных программ общедоступного класса. Время исполнения этого алгоритма в версии [10] составляет O(n4 log n), а реализации в [ ] – O(n3). Намного более эффективный алгоритм позднее предложили Бора и коллеги [2]. В их версии остовное дерево итеративно улучшается за счет подключения точки к ребру и последующего удаления самого длинного ребра в получившейся схеме. Время исполнения этого алгоритма в наихудшем случае составляет &(n2), также была предложена альтернативная реализация с временем O(n log n). Поскольку базовые структуры теперь уже не ограничены топологией МОД, эффективность данного подхода сравнялась с эффективностью итеративного алгоритма 1-Steiner [2]. Недавно был предложен новый эвристический алгоритм Мандуи и др. [11], основанный на 3/2-аппроксимации алгоритма вычисления метрического дерева Штейнера на квази-двудольных графах [ ]. Он работает несколько лучше итеративного алгоритма 1-Steiner, но слегка уступает этому же алгоритму в случае использования последним проверки на пустые прямоугольники [11]. Недавно Чу [3], а также Чу и Вонг [4] предложили эффективный подход на базе таблицы поиска для построения прямолинейного дерева Штейнера.
В силу высокой значимости этой задачи для ее решения было разработано немало алгоритмов, которые можно разбить на два класса: точные и эвристические. Поскольку задача SMT является NP-полной, любой точный алгоритм будет иметь ожидаемое экспоненциальное время выполнения в наихудшем случае. Однако в этой области были достигнуты два значительных улучшения. Одним из них стал алгоритм GeoSteiner в реализации Уорма, Уинтера и Захарисена [14, 15] – самый быстрый на данный момент точный алгоритм для решения этой задачи. Второй алгоритм, аппроксимационная схема с полиномиальным временем выполнения (Polynomial Time Approximation Scheme, PTAS) Ароры [1], имеет скорее теоретическую значимость. Поскольку время выполнения точных алгоритмов получается очень долгим, особенно для входных данных большого объема, намного больше внимания было уделено разработке эвристических алгоритмов. Многие из них генерируют дерево Штейнера посредством улучшения топологии [[минимальное остовное дерево|минимального остовного дерева]] (MST) [7], так как было доказано, что MST является 3/2-аппроксимацией SMT [8]. Однако из-за того, что в этих подходах базовые структуры ограничены топологией минимального остовного дерева, степень улучшений по сравнению с ним ограничена. Итерационный алгоритм 1-Steiner Канга и Робинса [10] был одной из первых попыток обойти это ограничение, а его улучшенная реализация [6] стала самой популярной из подобных программ общедоступного класса. Время выполнения этого алгоритма в версии [10] составляет <math>O(n^4 \; log \; n)</math>, а реализации в [6] – <math>O(n^3) \;</math>. Намного более эффективный алгоритм позднее предложили Бора и коллеги [2]. В их версии остовное дерево итеративно улучшается за счет подключения точки к ребру и последующего удаления самого длинного ребра в получившейся схеме. Время выполнения этого алгоритма в наихудшем случае составляет <math>\Theta(n^2) \;</math>, также была предложена альтернативная реализация с временем <math>O(n \; log \; n)</math>. Поскольку базовые структуры теперь уже не ограничены топологией МОД, эффективность данного подхода сравнялась с эффективностью итеративного алгоритма 1-Steiner [2]. Недавно был предложен новый эвристический алгоритм Мандуи и др. [11], основанный на 3/2-аппроксимации алгоритма вычисления метрического дерева Штейнера на квази-двудольных графах [12]. Он работает несколько лучше итеративного алгоритма 1-Steiner, но слегка уступает этому же алгоритму в случае использования последним проверки на пустые прямоугольники [11]. Недавно Чу [3], а также Чу и Вонг [4] предложили эффективный подход на базе таблицы поиска для построения прямолинейного дерева Штейнера.


== Основные результаты ==
Представленный алгоритм основан на эвристике подстановки ребер, предложенной Борой и коллегами [2] и работающей следующим образом. Эвристика начинает работу с имеющегося минимального остовного дерева и итеративно рассматривает возможность подключения точки (например, p на рис. 1) к ближайшему ребру (например, (a, b)) и удаления самого длинного ребра (b, c)) из получившейся схемы. Алгоритм использует [[остовный граф]] [17] как базовую структуру вычисления: вначале он используется для генерации исходного минимального остовного дерева, а затем – пар «точка-ребро» для улучшения этого дерева. Подобная унификация наблюдается также при вычислении остовного дерева и самого длиного ребра для каждой пары «точка-ребро»: эти два вычисления объединяет использование алгоритма Крускала для операций на непересекающихся множествах [5] вместо алгоритма Прима.


Рисунок 1. Подстановка ребра в алгоритме Боры и др.


[[Файл:RST2_1.png]]


Рисунок 2. Минимальное остовное дерево и его бинарное дерево слияния.
Рисунок 1. Подстановка ребра в алгоритме Боры и др.




== Основные результаты ==
Для сокращения количества потенциальных пар «точка-ребро» с <math>O(n^2) \;</math> до <math>O(n) \;</math> Бора и коллеги предложили использовать параметр видимости точки со стороны ребра: только точка, видимая от ребра, может рассматриваться для подключения к нему. Для поиска отношений видимости между точками и ребрами необходим заметающий алгоритм. Чтобы избежать выполнения этого сложного этапа, используется информация о геометрической близости, встроенная в остовный граф. Поскольку у точки имеется восемь ближайших точек, подключенных вблизи нее, то можно заметить: если точка видима от ребра, то она обычно подключена в графе по меньшей мере к одной из конечных точек ребра. Алгоритм использует остовный граф для генерации пар-кандидатов «точка-ребро». Для каждого ребра текущего дерева все точки, являющиеся соседями одной из конечных точек ребра, будут рассматриваться в качестве потенциальных кандидатов на подключение к ребру. Поскольку мощность остовного графа составляет O(n), количество возможных пар, сгенерированных таким образом, также укладывается в эту оценку.
Представленный алгоритм основан на эвристике подстановки ребер, предложенной Борой и коллегами [ ]. и работающей следующим образом. Эвристика начинает работу с имеющегося минимального остовного дерева и итеративно рассматривает возможность подключения точки (см. рис. 1) к ближайшему ребру (например, (a, b)) и удаления самого длинного ребра (b, c)) из получившейся схемы. Алгоритм использует остовный граф [ ] как базовую структуру вычисления: вначале он используется для генерации минимального остовного дерева, а затем – пар «точка-ребро» для улучшения этого дерева. Подобная унификация наблюдается также при вычислении остовного дерева и самого длиного ребра для каждой пары «точка-ребро»: эти два вычисления объединяет использование алгоритма Крускала для операций на непересекающихся множествах [5] вместо алгоритма Прима.




Для сокращения количества потенциальных пар «точка-ребро» с O(n2) до O(n) Бора и коллеги предложили использовать параметр видимости точки со стороны ребра: только точка, видимая от ребра, может рассматриваться для подключения к нему. Для поиска отношений видимости между точками и ребрами необходим заметающий алгоритм. Чтобы избежать выполнения этого сложного этапа, используется информация о геометрической близости, встроенная в остовный граф. Поскольку у точки имеется восемь ближайших точек, подключенных вблизи нее, то можно заметить: если точка видима от ребра, то она обычно подключена в графе по меньшей мере к одной из конечных точек ребра. Алгоритм использует остовный граф для генерации пар-кандидатов «точка-ребро». Для каждого ребра текущего дерева все точки, являющиеся соседями как минимум одной из конечных точек ребра, будут рассматриваться в качестве потенциальных пар. Поскольку мощность остовного графа составляет O(n), количество возможных пар, сгенерированных таким образом, также укладывается в эту оценку.
При подключении точки к ребру самое длинное ребро получившейся схемы необходимо удалить. Для эффективного поиска соответствующего самого длиного ребра для каждой пары «точка-ребро» используется подход к вычислению остовного дерева при помощи алгоритма Крускала. Этот алгоритм сортирует ребра в порядке неубывания длины и рассматривает поочередно каждое ребро. Если конечные точки ребра были соединены, оно исключается из остовного дерева; в противном случае ребро включается в остовное дерево. Структура операций подключения может быть представлена бинарным деревом, листьями которого являются точки, а внутренними вершинами – ребра. После включения ребра в остовное дерево создается вершина, представляющая ребро, а также два ее потомка-дерева, представляющие два компонента, соединенные этим ребром. Пример остовного дерева и представляющего его бинарного дерева приведен на рис. 2. Легко увидеть, что самое длинное ребро между двумя точками является наименьшим общим предком этих двух точек в бинарном дереве. Например, самое длинное ребро между точками p и b на рис. 2 – ребро (b, c), наименьший общий предок p и b в бинарном дереве. Чтобы найти самое длинное ребро в схеме, образованной подключением точки к ребру, необходимо найти самое длинное ребро между этой точкой и той из конечных точек ребра, с которой она находилась в одном компоненте до подключения к ребру. Например, рассмотрим пару из точки p и ребра (a, b). Поскольку p и b принадлежали к одному компоненту до подключения (a, b), самым длинным ребром оказывается ребро между p и b; его и нужно удалить.




При подключении точки к ребру самое длинное ребро получившейся схемы необходимо удалить. Для эффективного поиска соответствующего самого длиного ребра для каждой пары «точка-ребро» используется подход к вычислению остовного дерева при помощи алгоритма Крускала. Этот алгоритм сортирует ребра в порядке неубывания длины и рассматривает поочередно каждое ребро. Если конечные точки ребра были соединены, оно исключается из остовного дерева; в противном случае ребро включается в остовное дерево. Структура операций подключения может быть представлена бинарным деревом, листьями которого являются точки, а внутренними вершинами – ребра. После включения ребра в остовное дерево создается вершина, представляющая ребро, а также два ее потомка, представляющие два компонента, соединенные этим ребром. Пример остовного дерева и представляющего его бинарного дерева приведен на рис. 2. Легко увидеть, что самое длинное ребро между двумя точками является наименьшим общим предком этих двух точек в бинарном дереве. Например, самое длинное ребро между точками p и b на рис. 2 – ребро (b, c), наименьший общий предок p и b в бинарном дереве. Чтобы найти самое длинное ребро в схеме, образованной подключением точки к ребру, необходимо найти самое длинное ребро между этой точкой и той из конечных точек ребра, с которой она находилась в одном компоненте до подключения к ребру. Например, рассмотрим пары из точки p и ребра (a, b). Поскольку p и b принадлежали к одному компоненту до подключения (a, b), самым длинным ребром оказывается ребро между p и b; его и нужно удалить.
[[Файл:RST2_2.png]]


Рисунок 2. Минимальное остовное дерево и его бинарное дерево слияния.


T = ;;
Сгенерировать остовный граф G при помощи алгоритма RSG;
for (каждой дуги (u, v) 2 G по порядку неубывания длины) {
s1 = find_set(u); s2 = find_set(v);
if (s1!=s2){
добавить (u, v) в дерево T;
for (каждого соседа w точек u, v в G)
if (s1 == find_set(w))
lca_add_query(w; u; (u, v));
else lca_add_query(w; v; (u, v));
lca_tree_edge((u, v), s1.edge);
lca_tree_edge((u, v), s2.edge);
s = union_set(s1; s2); s.edge = (u, v);
}
}
сгенерировать пары «точка-ребро» на основе lca_answer_queries;
for (каждой пары (p; (a; b); (c; d)) в порядке невозрастания положительного прироста)
if (ребро (a; b); (c ;d) не было удалено из T) {
подключить p к (a, b), добавив три ребра к T;
удалить (a; b); (c; d) из T;
}


Рисунок 3. Алгоритм построения прямолинейного дерева Штейнера.
На основе вышеприведенных рассуждений создан псевдокод алгоритма, представленный на рис. 3. На начальном этапе работы алгоритма для генерации остовного графа G для заданного множества точек используется алгоритм построения прямолинейного остовного графа Чжоу и др [17]. Затем к графу применяется алгоритм Крускала для генерации минимального остовного дерева. Структура данных на основе непересекающихся множеств [5] используется для слияния компонентов и проверки, принадлежат ли две точки к одному и тому же компоненту (первый цикл '''for'''). В процессе выполнения также генерируются бинарное дерево слияния и запросы по поводу наименьших общих предков для всех пар «точка-ребро». Здесь s, s1 и s2 представляют непересекающиеся множества, каждое из которых хранит корень компонента в бинарном дереве слияния. При каждом добавлении дуги (u, v) к T следует рассматривать любого соседа u или v, обозначим его за w, как кандидата на подключение к (u, v). Самое длиное ребро для этой пары будет наименьшим общим предком w и u либо w и v, в зависимости от того, какая точка оказывается в одном компоненте с точкой w. Добавление этого опроса производится при помощи процедуры lca_add_query. Соединение двух компонентов посредством (u, v) также будет записано в бинарном дереве слияния при помощи процедуры lca_tree_edge. После генерации минимального остовного дерева у нас также имеются соответствующее бинарное дерево слияния и запросы по поводу наименьших общих предков. При помощи оффлайнового алгоритма Тарьяна для нахождения наименьших общих предков [5] (представленного процедурой lca_answer_queries) можно сгенерировать все самые длинные ребра для пар. При наличии информации о самом длинном ребре для каждой пары «точка-ребро» можно решить задачу подключения точки к ребру. После этого можно осуществить подключения точек к ребрам в порядке невозрастания прироста. Подключение может быть осуществлено только в случае, если ни ребро подключения, ни ребро удаления еще не были удалены.




На основе вышеприведенных рассуждений создан псевдокод алгоритма, представленный на рис. 3. На начальном этапе работы алгоритма для генерации остовного графа G для заданного множества точек используется алгоритм построения прямолинейного остовного графа Чжоу и др [17]. Затем к графу применяется алгоритм Крускала для генерации минимального остовного дерева. Структура данных на основе непересекающихся множеств [ ] используется для слияния компонентов и проверки, принадлежат ли две точки к одному и тому же компоненту (первый цикл for). В процессе выполнения также генерируются бинарное дерево слияния и запросы по поводу наименьших общих предков для всех пар «точка-ребро». Здесь s, s1 и s2 представляют непересекающиеся множества, каждое из которых хранит корень компонента в бинарном дереве слияния. При каждом добавлении дуги (u, v) к T следует рассматривать любого соседа u или v, обозначим его за w, как кандидата на подключение к (u, v). Самое длиное ребро для этой пары будет наименьшим общим предком w и u либо w и v, в зависимости от того, какая точка оказывается в одном компоненте с точкой w. Добавление этого опроса производится при помощи процедуры lca_add_query. Соединение двух компонентов при помощи (u, v) также будет записано в бинарном дереве слияния при помощи процедуры lca_tree_edge. После генерации минимального остовного дерева у нас также имеются соответствующее бинарное дерево слияния и запросы по поводу наименьших общих предков. При помощи оффлайнового алгоритма Тарьяна для нахождения наименьших общих предков [ ] (представленного процедурой lca_answer_queries) можно сгенерировать все самые длинные ребра для пар. При наличии информации о самом длинном ребре для каждой пары «точка-ребро» можно решить задачу подключения точки к ребру. После этого можно осуществить подключения точек к ребрам в порядке невозрастания прироста. Подключение может быть осуществлено только в случае, если ни ребро подключения, ни ребро удаления еще не были удалены.
Большую часть времени выполнения алгоритма занимают генерация остовного графа и сортировка ребер, требующие O(n log n) времени. Поскольку количество ребер в остовном графе составляет O(n), и алгоритм Крускала, и алгоритм Тарьяна для поиска наименьших общих предков занимают <math>O(n \alpha (n)) \;</math> времени, где <math>\alpha (n) \;</math> – обратная функция Аккермана, растущая исключительно медленно.




Большую часть времени исполнения алгоритма занимают генерация остовного графа и сортировка ребер, требующие O(n log n) времени. Поскольку количество ребер в остовном графе составляет O(n), и алгоритм Крускала, и алгоритм Тарьяна для поиска наименьших общих предков занимают O{na{n)) времени, где a{n) – обратная функция Аккермана, растущая исключительно медленно.
  <math>T = \empty</math>;
  Сгенерировать остовный граф G при помощи алгоритма RSG;
  '''for''' (каждой дуги <math>(u, v) \in G \;</math> по порядку неубывания длины) {
      s1 = find_set(u); s2 = find_set(v);
      '''if''' (s1 != s2) {
        добавить (u, v) в дерево T;
        '''for''' (каждого соседа w точек u, v в G)
            '''if''' (s1 == find_set(w))
                  lca_add_query(w, u, (u, v));
            '''else''' lca_add_query(w, v, (u, v));
        lca_tree_edge((u, v), s1.edge);
        lca_tree_edge((u, v), s2.edge);
        s = union_set(s1, s2); s.edge = (u, v);
      }
  }
  сгенерировать пары «точка-ребро» при помощи lca_answer_queries;
  '''for''' (каждой пары (p, (a, b), (c, d)) в порядке невозрастания положительного прироста)
      '''if''' (ребро (a, b), (c ,d) не было удалено из T) {
        подключить p к (a, b), добавив три ребра к T;
        удалить (a, b), (c, d) из T;
      }


Рисунок 3. Алгоритм построения прямолинейного дерева Штейнера.


== Применение ==
== Применение ==
Строка 62: Строка 64:


== Экспериментальные результаты ==
== Экспериментальные результаты ==
Как отмечалось в работе [ ], первая серия экспериментов была проведена на Linux-системе с процессором Intel Pentium III с тактовой частотой 938 МГц и 512 Мбайт оперативной памяти. Алгоритм RST сравнивался с другими публично доступными программами: точным алгоритмом GeoSteiner (версия 3.1) Уорма, Уинтера и Захарисена [ ], пакетным итеративным алгоритмом 1-Steiner (BI1S) Робинса и алгоритмом Боры и коллег, реализованным Мэдденом (BOI).
Как отмечалось в работе [16], первая серия экспериментов была проведена на Linux-системе с процессором Intel Pentium III с тактовой частотой 928 МГц и 512 Мбайт оперативной памяти. Алгоритм RST сравнивался с другими публично доступными программами: точным алгоритмом GeoSteiner (версии 3.1) Уорма, Уинтера и Захарисена [14], пакетным итеративным алгоритмом 1-Steiner (Batched Iterated 1-Steiner, BI1S) Робинса и алгоритмом Боры и коллег, реализованным Мэдденом (BOI).




В таблице 1 приведены результаты первой серии экспериментов. Для каждого экземпляра входных данных объемом от 100 до 5000 точек при помощи программы rand_points пакета GeoSteiner было случайно сгенерировано 30 различных тестовых сценариев. Коэффициент улучшения алгоритма вычисления дерева Штейнера St по сравнению с соответствующим алгоритмом вычисления минимального остовного дерева MST определяется как 100 x (MST - St)/MST. Для каждого варианта объема входных данных были вычислены средние значения коэффициента улучшения и времени исполнения (в секундах) каждой из программ. Легко увидеть, что RST всегда обеспечивает более высокую эффективность по сравнению с BOI при меньшей продолжительности работы.
В таблице 1 приведены результаты первой серии экспериментов. Для каждого экземпляра входных данных объемом от 100 до 5000 точек при помощи программы rand_points пакета GeoSteiner было случайно сгенерировано 30 различных тестовых сценариев. Коэффициент улучшения алгоритма вычисления дерева Штейнера St по сравнению с соответствующим алгоритмом вычисления минимального остовного дерева MST определяется как 100 x (MST - St)/MST. Для каждого варианта объема входных данных были вычислены средние значения коэффициента улучшения и времени выполнения (в секундах) каждой из программ. Легко увидеть, что RST всегда обеспечивает более высокую эффективность по сравнению с BOI при меньшей продолжительности работы.




Во второй серии экспериментов сравнивались алгоритмы RST, версия Боры его собственного алгоритма (Borah), алгоритм Роэ на базе подхода Прима (Rohe) [ ] и жадный пакетный алгоритм Канга и др. (Batched Greedy Algorithm, BGA) [ ]. Они исполнялись на различных Linux-системах с процессором Intel Xeon с 2,4 ГГц тактовой частоты и 2 ГБ оперативной памяти. Помимо случайно сгенерированных тестовых сценариев, также использовались промышленные тестовые сценарии из области разработки СБИС [9]. Результаты представлены в таблице 2.
Во второй серии экспериментов сравнивались алгоритмы RST, версия Боры его собственного алгоритма (Borah), алгоритм Роэ на базе подхода Прима (Rohe) [13] и жадный пакетный алгоритм Канга и др. (Batched Greedy Algorithm, BGA) [9]. Они выполнялись на различных Linux-системах с процессором Intel Xeon с 2,4 ГГц тактовой частоты и 2 ГБ оперативной памяти. Помимо случайно сгенерированных тестовых сценариев, также использовались промышленные тестовые сценарии из области разработки СБИС [9]. Результаты представлены в таблице 2.


{| class = "wikitable"
{| class = "wikitable"
Строка 75: Строка 77:
  ! colspan="2" width="200" | BI1S
  ! colspan="2" width="200" | BI1S
  ! colspan="2" width="200" | BOI
  ! colspan="2" width="200" | BOI
  ! colspan="2" width="200" | RSt
  ! colspan="2" width="200" | RST
  |-  
  |-  
  ! | улучш.
  ! | улучш.
Строка 88: Строка 90:
  | 100||11,440||0,487||10,907||0,633||9,300||0,0267||10,218||0,004
  | 100||11,440||0,487||10,907||0,633||9,300||0,0267||10,218||0,004
  |-  
  |-  
  | 200||11,492|3,557||10,897||4,810||9,192||0,1287||10,869||0,020
  | 200||11,492||3,557||10,897||4,810||9,192||0,1287||10,869||0,020
  |-  
  |-  
  | 300||11,492||12,685||10,931||18,770||9,253||0,2993||10,255||0,041
  | 300||11,492||12,685||10,931||18,770||9,253||0,2993||10,255||0,041
Строка 113: Строка 115:
  ! colspan="2" width="200" | BI1S
  ! colspan="2" width="200" | BI1S
  ! colspan="2" width="200" | BOI
  ! colspan="2" width="200" | BOI
  ! colspan="2" width="200" | RSt
  ! colspan="2" width="200" | RST
  |-  
  |-  
  ! | улучш.
  ! | улучш.
Строка 165: Строка 167:


== См. также ==
== См. также ==
* ''[Прямолинейное остовное дерево]
* ''[[Прямолинейное остовное дерево]]
 


== Литература ==
== Литература ==
4430

правок