Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
7_Задачи на графах.doc
Скачиваний:
13
Добавлен:
07.02.2016
Размер:
113.66 Кб
Скачать

2. Связность

Известны два классических алгоритма установления связности обыкновенный графов.

Алгоритм Крускала (Kruskal)

Пусть имеем граф g=(V,X). Пусть Т – подмножество ребер графа g, которое вначале пустое. Добавим к Т первое попавшееся ребро, если оно не образует цикл с уже имеющимися в Т ребрами. Продолжим процесс до исчерпания подходящих ребер. Если после завершения процесса число ребер в Т равно n-1 , тогда граф g связный.

Алгоритм Прима (Prim)

Пусть имеем граф g=(V,X). Пусть Т – подмножество его ребер вместе с конечными вершинами, которое вначале пустое. Добавим к Т первое попавшееся ребро. Далее, будем добавлять к Т ребро, одна вершина котрого находится в Т, а другая за пределами Т. Если по завершении процесса число ребер в Т равно n-1 , граф связный.

Определение связности на основе волнового процесса

Процедуру определения связности графа можно построить на основе первого волнового процесса. Выберем произвольную вершину a и будем считать, что V0={a}. Выполним разметку (индексирование) вершин на основе волнового процесса 1. Если размеченными оказались все вершины, то граф является связным.

Пусть <V0,V1, ... , Vs> - разбиение множества вершин графа, получемое в результате волнового процесса и пусть vi – вершина номер i графа g, а vik – вершина, имеющая номер k в пределах подмножества Vi . Тогда анализ процедуры волнового процесса дает следующее соотношение для времени его выполнения:

,

где n – число вершин, r – число ребер, p(vik), p(vi) – степень вершины, s – количество подмножеств, порождаемых волновым процессом. Отсюда для нашего алгоритма получаем:

t = F(n) = O(r).

Таким образом, по времени выполнения, последний алгоритм имеет такую же эффективность, как и алгоритмы Крускала и Прима.

Определение компонент связности

Следующий алгоритм позволяет определить все компоненты связности графа.

1. Выбрать произвольно вершину a заданного графа g = (V,X). Полагая V0={a}выполнить волновой процесс с индексированием вершин и пусть V0,V1, ... , V - полученная при этом последовательность подмножеств. Разделим множество вершин V на два подмножества: U1 = V0V, ... , V и U2 = V - U1 .

2. Выделить подграф g1 на подмножестве вершин U1 и подграф g2 на подмножестве вершин U2 . Подграф g1 – полученный компонент связности графа g.

3. Если U2   выполнить п.1 для подграфа g2, иначе – алгоритм завершить.

3. Задачи о кратчайших маршрутах

Пусть дан граф g = (V,X) и две его вершины a, bV. Имеется 4 вида задач о кратчайших маршрутах.

1 Найти длину кратчайшего маршрута из вершины a в вершину b.

2 Найти маршрут минимальной длины из a в b.

3 Найти количество кратчайших маршрутов из a в b.

4 Найти множество всех кратчайших маршрутов из a в b.

Под длиной маршрута в графе понимают количество ребер, его составляющих.

Алгоритмы решения указанных задач могут быть построены на основе волновых процессов.

Задача о кратчайших маршрутах относятся к классу P.

Задача 1

Будем выполнять волновой процесс 1 начиная с V0 = {a}. Завершим его в том случае, если очередное подмножество Vk будет включать вершину b. Индекс k этого подмножества и будет искомой длиной кратчайшего пути.

Ниже, в качестве примера программной реализации такого алгоритма, приведена функция dist(g,i,m) из библиотеки ALGRAPH/C++ (в несколько упрощенном варианте), которая находит длину кратчайшего маршрута из вершины i в вершину m. Если маршрут для указанных вершин отсутствует, функция возвращает значение -1.

int dist(graf g, int i, int m)

{ int a,b,j,k,Nvv,Nw, L=0, n=g.nv;

if (i==m) return 0;

if (g.p[i]==0) return -1;

byte* Vs= new byte[n];

int *vv= new int[n],

*w = new int[n];

for (k=0;k<n;k++) Vs[k]=0;

Vs[i]=1; vv[0]=i; Nvv=1;

while (Nvv)

{ Nw=0; L++;

for (j=0;j<Nvv;j++)

{ a=vv[j];

for (k=0;k<g.p[a];k++)

{ b=g.r[a][k]; if (b==m) goto mm;

if (Vs[b]==0) { Vs[b]=1; w[Nw++]=b; }

}

}

for (j=0;j<Nw;j++) vv[j]=w[j];

Nvv=Nw;

}

L=-1;

mm:

delete[] Vs; delete[] vv; delete[] w;

return L;

}

Задача 2

Алгоритм поиска кратчайшего пути следует из свойств 2,3 волнового процесса 2.

Задача 3

Выполним волновой процесс 2. В результате получим последовательность подмножеств вершин V'0, V'1, ... , V'k, при этом V'0 = {a}, V'k = {b}. Пронумеруем вершины в каждом из подмножеств независимо. Каждой вершине из указанных подмножеств припишем два индекса так, чтобы запись vij обозначала вершину номер j из подмножества V'i. Очевидно, что v0,1 = a, vk,1 = b. Обозначим через (vij) вес вершины vij. Каждой вершине из подмножеств V'0, V'1, ... , V'k присвоим вес в соответствии со следующим правилом.

1. Положим (v0,1) = 1 .

2. , i = 0, 1, ... , k-1 .

Суммирование необходимо выполнять по всем значениям m, удовлетворяющих условию:

<vi,m , vi+1 , j>  X .

Пункт 2 означает, что вес вершины vi+1 , j определяется как сумма индексов всех тех вершин из множества V'i , которые являются начальными по отношению к вершине vi+1 , j.

При выполнении п.2 следует соблюдать очередность: вначале определяются веса всех вершин из множества V'i, затем веса всех вершин из следующего за ним множества V'i+1 .

После завершения процедуры вес конечной вершины (vk,1) = (b) будет равен искомому количеству кратчайших путей.

Задача 4

Алгоритм решения этой задачи вытекает из свойства 3 волнового процесса 2.