Поиск пути между парой вершин невзвешенного графа
Пусть мы имеем произвольный граф, ориентированный или неориентированный. Если в невзвешенном графе существует путь, то назовем длиной пути количество ребер в нем. Если пути нет вообще, то расстояние считается бесконечным. Путь минимальной длины при этом называется кратчайшим путем в графе. Легко показать, что любые части кратчайшего пути также являются кратчайшими путями между соответствующими вершинами. Ведь если это не так, то есть существует отрезок кратчайшего пути, между концами которого можно построить более короткий путь, то мы можем заменить этот отрезок кратчайшего пути между вершинами u и v на более короткий, тем самым уменьшив и длину кратчайшего пути между u и v, что невозможно. Это свойство кратчайших путей позволяет решать задачу их нахождения методом динамического программирования. Покажем сначала как можно записать “волновой алгоритм” так, что задача поиска кратчайшего пути между двумя вершинами графа будет решаться за O (N 2) действий. Задача 12. Для линий метрополитена некоторого города известно, между какими парами линий есть пересадочная станция. Необходимо определить, за сколько пересадок можно добраться с линии m на линию n или сообщить, что сделать это невозможно. Решение. Такой метрополитен удобно описывать с помощью графа, вершины которого есть линии метрополитена (а не станции!!!), а наличие ребра между вершинами i и j графа соответствует наличию пересадочной станции между линиями с номерами i и j. Представим этот граф с помощь массива множеств (переменная ss в программе), в i -м элементе этого массива содержится множество всех линий, на которые можно попасть с линии i за одну пересадку. Результат будем получать с помощью множества s, на каждом шаге алгоритма содержащего номера всех линий, на которые можно попасть с исходной линии m за k пересадок. Заметим, что если вершина n нашего графа достижима из вершины m (говорят, что они находятся в одной компоненте связности), то искомое число пересадок меньше общего количества линий nn. Так как даже если после каждой из первых nn – 1 пересадок мы попадали на новую линию, то после следующей пересадки мы обязательно окажемся на какой-то из линий повторно, ведь их всего nn. Поэтому, если наш алгоритм не завершился за nn – 1 шаг, то граф не связан и дальнейший поиск пути бесполезен (заметим, что наличие пути между двумя конкретными вершинами не доказывает его связность, а исследовать все пары вершин с помощью предложенного алгоритма для анализа связности неэффективно).
Программа для решения задачи представлена ниже.
const nn=200;{число линий} type myset = set of 0..nn;var i,m,n,k:byte; ss:array[1..nn] of myset; s,s1:myset;begin …{считываем входные данные} s:=[m]; k:=0; while not (n in s) and(k<nn-1) do begin k:=k+1; s1:=s; s:=[]; for i:=1 to nn do if i in s1 then {добавляем к s вершины, достижимые из i} s:=s+ss[i] end; if n in s then writeln(k) else writeln('it is impossible') end.
Заметим, что предложенный при решении задачи 12 алгоритм можно модифицировать так, чтобы он находил длину кратчайшего пути от исходной вершины до всех других вершин графа, причем асимптотическое время его работы не изменится. Несмотря на хорошие временные характеристики, область применения алгоритма ограничена размером типа “множество” в Паскале. Избежать этого ограничения можно, используя такой способ представления графа как массив списков вершин, смежных с данной. О способах реализации динамических структур данных, и в частности списков, см., например, [8]. Пусть теперь требуется определить наличие пути сразу для всех пар вершин графа. Такая задача для невзвешенного графа называется транзитивным замыканием. Рассмотрим ее решение на примере следующей проблемы.
Задача 13. Пусть для некоторых пар переменных известно, что значение одной из них не больше значения другой. Выписать остальные пары из упомянутых переменных, для которых, используя транзитивность операции “£”, можно также сказать, значение одной из них не превосходит значение другой. Решение. Обозначим данными переменными вершины графа, а знание о наличии между двумя переменными отношения “£” — ориентированными ребрами. Для некоторой пары вершин справедливо, что значение одной £ значения другое, если в построенном ориентированном графе существует путь из первой из упомянутых вершин во вторую. Тогда для решения задачи можно воспользоваться следующим алгоритмом Уоршолла [5, 6]. Пусть A — матрица, изначально равная матрице смежности графа, записанной с помощью логических констант true и false. На k -м шаге алгоритма значение true в элементе матрицы A [ i, j ] будет означать, что из вершины i в вершину j cуществует путь, который проходит через некоторые вершины с номерами, не превосходящими k – 1. Если же через упомянутые вершины пути нет(A [ i, j ] = false), но существует путь из вершины i в вершину k и путь из вершины k в вершину j то значение данного элемента матрицы становится true. Покажем как написать фрагмент программы, реализующий этот алгоритм без использования условных операторов:
c:=a;{запоминаем матрицу смежности} for k:=1 to nn do for i:=1 to nn do for j:=1 to nn do a[i,j]:=a[i,j] or a[i,k] and a[k,j];
Краткость говорит здесь сама за себя. В результате выполнения трех вложенных циклов (то есть мы имеем алгоритм, работающий за N 3 операций), порядок которых очень важен, в матрице a мы фактически получим ответ на вопрос задачи. Распечатать его можно так:
for i:=1 to nn do for j:=1 to nn do if a[i,j] xor c[i,j] then writeln(i,’ ’,j);
Если же требуется найти длины кратчайших путей для всех пар вершин, то, если каждому ребру графа приписать вес, равный единице, решение задачи будет полностью совпадать с решением той же задачи для взвешенного графа (см. далее). Поэтому отдельно мы рассматривать его не будем.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|