насыщенном графе

advertisement
Выполнила Кулагина С.О.
ОПРЕДЕЛЕНИЯ


Будем рассматривать задачу в терминах ориентированных графов.
Граф – конечное множество V, называемое множеством вершин, на
котором задано симметричное антирефлексивное отношение R и
выделено множество E двухэлементных подмножеств V, определяемое
как {a,b}€ E тогда и только тогда, когда (a,b) € R и a ≠ b, и (b,a) не входит
в Е.

Вес – параметр дуги, длина дуги.

Путь – сумма длин входящих в него дуг.

Полустепенью исхода(захода) называется число исходящих (входящих)
дуг.

Две вершины – смежные, если они соединены дугой.

Длина пути(во взвешенном графе) – ∑ весов дуг графа.

Цикл – путь, который начинается и заканчивается в одной той же
вершине и содержит как минимум 1 дугу.

Ациклическим считается граф, не содержащий ни одного цикла.

В разреженном графе m<<n2, где m – число дуг, n – число вершин.

Иначе , m=c*n, где с – константа, с≤4.

В насыщенном графе m≈n2 или
m ≈ c*n2 , где с – константа, с<1.
СТРУКТУРА БИБЛИОТЕКИ STL
Библиотека содержит пять основных видов компонентов:
* алгоритм (algorithm): определяет вычислительную
процедуру.
* контейнер (container): управляет набором объектов в
памяти.
* итератор (iterator): обеспечивает для алгоритма
средство доступа к содержимому контейнера.
* функциональный объект (function object):
инкапсулирует функцию в объекте для использования
другими компонентами.
* адаптер (adaptor): адаптирует компонент для
обеспечения различного интерфейса.
3 ВОЗМОЖНЫХ ПРЕДСТАВЛЕНИЯ
•
•
Матрица смежности(vector<vector<int> >)
– для насыщенного графа
Структура смежности(vector< list<int> > )
–
•
Для разреженного графа
Представление в форме map
–
Для представления при входе
ИСПОЛЬЗУЕМЫЕ КЛАССЫ БИБЛИОТЕКИ.
Для создания
векторовструктур,
аналогичных
массивам, но
имеющих
большую
функциональ
ность
Для вводавывода
Для
представления
графа в виде
матрицы
Для создания
строк
Для создания
списков
Для
определения
функторов
Для
создания
очередей(на
пример, для
хранения
вершин)
ПРЕДСТАВЛЕНИЕ ГРАФА: ВАРИАНТ1

Если граф взвешенный:
Представление графа в виде массива дуг с помощью STL map.
 Дуге(из 2-х вершин) сопоставляется её вес.


Пример: представление визуальное и в форме map
Пример:
map<string, list<int> >::iterator it;
// Создание итератора для перехода
по map
Int i =10;
it->first.push_back(i);// первая вершина
Используем это представление для упорядочения графа на входе в программу
ПРЕДСТАВЛЕНИЕ ГРАФА: ВАРИАНТ 2

Если граф насыщенный:
Используется двумерная матрица смежности A.
 Для дуги (vi,wj) с весом ci,j

A[i][j] = ci,j
Несуществующие дуги – значение «бесконечность»
 В STL представляется как vector<vector<int> >

ПРЕДСТАВЛЕНИЕ ГРАФА : ВАРИАНТ 3

Если граф разреженный и связный:
№ вершины
Список смежных вершин

Используется структура смежности:
массив списков.
Вес
vector< list<int> >
соответствующей
дуги
vector<list<int>>::iterator
it = new interator;
Хранится вектор вершин, которым
сопоставлены списки номеров вершин,
смежных с ними.
Будем представлять граф именно так.
ОБХОД В ШИРИНУ
oАлгоритм:
Выбираем непройденную вершину.
Проверяем все рёбра и запоминаем
непройденные вершины на их концах.
Выбираем непройденную вершину и
повторяем действия.
ОБХОД В ШИРИНУ:КОД
typedef pair<int, bool> vertex;
typedef multimap<int, int>::iterator edgesIt;
vector<vertex> vertices;
multimap<int, int> edges;
deque<vertex> q;
while(1)
{
Вершина представлена парой значений:
номер и посещение
Очередь
реализована как
deque
current = q.front();
Текущая вершина –
первая в очереди
кандидатов
q.pop_front();
vector<vertex>::iterator vIt = find(vertices.begin(), vertices.end(), vertex(current.first, current.second));
(*vIt).second = true;
cout << "Visited: " << (*vIt).first << endl;
Проверка непустоты очереди
pair<edgesIt, edgesIt> rangeIt = edges.equal_range(current.first);
for(edgesIt eIt = rangeIt.first; eIt != rangeIt.second; eIt++)
{ if((find(vertices.begin(), vertices.end(), vertex((*eIt).second, true)) == vertices.end()) &&
(find(q.begin(), q.end(), vertex((*eIt).second, false)) == q.end())) {
push_back(vertex((*eIt).second, false));
cout << "To deque: " << (*eIt).second << endl;
}}
if(q.empty()) break;
}
cout << "End." << endl;
return EXIT_SUCCESS;}
Выход из цикла,
если все вершины
просмотрены
ОБХОД В ГЛУБИНУ

Алгоритм:

Выбираем непройденную вершину


Выбираем 1 из непройденных
смежных вершин
Если нет смежных непройденных
вершин, то помечаем вершину
пройденной и возвращаемся в
запомненную вершину.
ОБХОД В ГЛУБИНУ:КОД

Рекурсивная реализация:








vector < vector<int> > g; // граф
int n; // число вершин
vector<char> used;
void dfs (int v)
{ used[v] = true;
for (vector<int>::iterator i=g[v].begin(); i!=g[v].end(); ++i)
if (!used[*i]) dfs (*i);
}
Рекурсивный вызов
АЛГОРИТМ ДЕЙКСТРЫ
ЗАДАЧА
В ориентированном графе с заданными
длинами рёбер найти кратчайшие пути из
одной вершины во все остальные.
ОПРЕДЕЛЕНИЕ АЛГОРИТМА

Алгоритм:



Если – длина дуги (i,j).
Шаг 0. Помечаем нулевую вершину индексом 0
Шаг i. Помечаем вершину i индексом λi = min(λi+ λij).
НАЧАЛЬНЫЕ СТАДИИ АЛГОРИТМА
Придаём всем вершинам бесконечные веса
Отмечаем вершину - начало

Первый по очереди сосед вершины 1 — вершина 2, потому что длина
пути до нее минимальна. Длина пути в нее через вершину 1 равна
кратчайшему расстоянию до вершины 1 + длина ребра, идущего из 1 в
2, то есть 0 + 7 = 7. Это меньше текущей метки вершины 2, поэтому
новая метка 2-й вершины равна 7.
Аналогичную операцию проделываем с
двумя другими соседями 1-й вершины
— 3-й и 6-й.
Все соседи вершины 1 проверены. Текущее минимальное расстояние до
вершины 1 считается окончательным и обсуждению не подлежит (то, что
это действительно так, впервые доказал Дейкстра). Вычеркнем её из
графа, чтобы отметить, что эта вершина посещена. Выберем следующую
вершину



Снова пытаемся уменьшить метки соседей выбранной
вершины, пытаясь пройти в них через 2-ю. Соседями
вершины 2 являются 1, 3, 4.
Первый (по порядку) сосед вершины 2 — вершина 1. Но она
уже посещена, поэтому с 1-й вершиной ничего не делаем.
Следующий сосед вершины 2 — вершина 4. Если идти в неё
через 2-ю, то длина такого пути будет = кратчайшее
расстояние до 2 + расстояние между вершинами 2 и 4 = 7 + 15
= 22. Поскольку 22<, устанавливаем метку вершины 4 равной
22.
ПОВТОРЯЕМ АНАЛОГИЧНЫЕ
ВЕРШИН
ДЕЙСТВИЯ ДЛЯ ОСТАЛЬНЫХ

priority_queue<int, vector<int>, Cheapest> candidates;
while(1)


Очередь с
приоритетом
для кандидатов
{
for(list<int>::iterator p = outgoing_services[from].begin();
p!=outgoing_services[from].end();p++){

int b = cities[from]->total_distance+(*p)->distance;

int c = cities[from]->from_city;

if(cities[from]->visited==false){

if(cities[(*p)->destination]->total_fee==0)

{ cities[(*p)->destination]->total_fee = a;
Перебор по
спискам
смежности
cities[(*p)->destination]->from_city = c; }

else if(cities[(*p)->destination]->total_fee>a)
{ cities[(*p)->destination]->total_fee=a;

Присвоение
min значений
длины пути
Для
непосещённых
вершин
cities[(*p)->destination]->total_distance = b;

КОД
cities[(*p)->destination]->total_distance = b;

cities[(*p)->destination]->from_city = from;

candidates.push(cities[(*p)->destination]);


cities[from]->visited = true;

if (cities[to]->visited) {


}
}}
return pair<int,int>(cities[to]->total_fee, cities[to]->total_distance);}
Else { return pair<int,int>(INT_MAX, INT_MAX);
}
}
Добавляем
вершину –
«кандидата»
АЛГОРИТМ БЕЛЛМАНА-ФОРДА


Алгоритм Дейкстры - только в графе с
положительными весами дуг.
Для графа с отрицательными весами :
 как
 он

поступать с циклом с отрицательным весом?
делает большинство путей неопределными.
Так, путь от V2 до V5 не определён, потому что можно
попасть в петлю V3-V4-V1.
Эту проблему решает алгоритм БеллманаФорда
РЕАЛИЗАЦИЯ АЛГОРИТМА БЕЛЛМАНА-ФОРДА

Аналогична реализации алгоритма Дейкстры

Отличие:





If (элемент есть в очереди)
then она не включается повторно.
КОД.
If(find(candidates.begin(), candidates.end(), cities[(*p)>destination)==candidates.end())
candidates.push(cities[(*p)->destination]
Если очередь не содержит
кандидата, то он добавляется
АЦИКЛИЧЕСКИЕ ГРАФЫ


Задача поиска кратчайшего пути связана с
топологической сортировкой.
Топологическая сортировка упорядочивает вершины в
направленном ациклическом графе так, что




If (имеется путь из u в v)
then {v появляется после u в очерёдности.}
Она невозможна, если граф имеет хотя бы 1 цикл.
Описание:

Находится вершина, не имеющая входных дуг. Она и все
исходящие из неё дуги удаляются из графа.
АЛГОРИТМ
ТОПОЛОГИЧЕСКОЙ
СОРТИРОВКИ



Все непройденные
вершины с полустепенью
захода 0 добавляются в
очередь.
Чтобы получить
следующую вершину, мы
извлекаем первый
элемент из очереди.
Когда полустепень захода
элемента понижается до
0, он помещается в
очередь
КОД.
vector < vector<int> > g; // граф
int n; // число вершин
vector<bool> used;
vector<int> ans;
void dfs (int v) // процедура пометки непройденных вершин
{ used[v] = true;
for (vector<int>::itetator i=g[v].begin(); i!=g[v].end(); ++i)
if (!used[*i]) dfs (*i);
ans.push_back (v); }
void topological_sort (vector<int> & result)// сама сортировка
{ used.assign (n, false);
for (int i=0; i<n; ++i)
if (!used[i]) dfs (i);
result = ans; }
ИСПОЛЬЗОВАННАЯ ЛИТЕРАТУРА:

Data Structures and Problem Solving with C++ [2nd Ed] [M. A.
Weiss] [Addison Wesley]

Полный справочник по С++, Г.Шилдт

http://www.rsdn.ru/

http://e-maxx.ru/algo/

Дж. А. Андерсон, Дискретная математика и комбинаторика,
М:2004.
Download