Краткое описание алгоритма поиска в глубину
Алгоритм, как и при поиске в ширину, ищет кратчайший путь от заданной вершины до всех остальных. При этом обход осуществляется «в глубину» графа, то есть мы прыгаем на потомка, потом на следующего и так далее, пока есть куда углубляться. Как только достигнут «конец» возвращаемся на один уровень и опять углубляемся. Другими словами, мы не задерживаемся на одном уровне, а перемещаемся вверх и вниз.
В этой заметке я приведу реализацию самого обхода в глубину, но вся его прелесть в задачах, которые решаются с его помощью.
Моя реализация поиска в глубину на c++
Представление графа аналогично представлению в поиске в ширину. В виде списка смежности.
typedef vector<vector<int> > graphNotWeighted;
Далее буду представлены две реализации: с рекурсивным обходом и с линейным.
Исходный код алгоритма на c++
Функция инициирования обхода в глубину
Функция принимает граф и флаг, который указывает на рекурсивность обхода. Инициализирует все вспомогательные массивы и запускает процедуру обхода. Алгоритм работает через покраску вершин, подробно его описывать не буду, на википедии есть славная статья.
//Отметка времени
int currentTime = 0;
void DFSInit(graphNotWeighted &G, bool recursive) {
int n = G.size();
//Расстояние от i-ой вершины до стартовой
vector<int> distance(n, -1);
//Предок i-ой вершины на пути к стартовой
vector<int> prevTop(n, -1);
vector<int> time(n, -1);
//Цвет i-ой вершины
vector<char> topColor(n, 'w');
currentTime = 0;
for(int v = 0; v < n; v++) {
if(topColor[v] == 'w') {
if(recursive == true) {
DFSRecursive(G, v, distance, prevTop, time, topColor);
}
else {
DFSInStack(G, v, distance, prevTop, time, topColor);
}
}
}
//Print results
for (int i = 0; i < prevTop.size(); i++) {
cout << i << '(' << distance[i] << ',' << time[i] << ") :";
int x = prevTop[i];
while (x != -1) {
cout << x << ' ';
x = prevTop[x];
}
cout << endl;
}
cout << endl;
return;
}
Рекурсивный вариант обхода в глубину
void DFSRecursive(
graphNotWeighted &G,
int start,
vector<int> &distance,
vector<int> &prevTop,
vector<int> &time,
vector<char> &topColor) {
currentTime++;
distance[start] = currentTime;
topColor[start] = 'g';
for (int i = 0; i < G[start].size(); i++) {
int u = G[start][i];
if (topColor[u] == 'w') {
prevTop[u] = start;
DFSRecursive(G, u, distance, prevTop, time, topColor);
}
}
topColor[start] = 'b';
currentTime++;
time[start] = currentTime;
return;
}
Нерекурсивный вариант обхода в глубину с использованием стека
void DFSInStack(
graphNotWeighted &G,
int start,
vector<int> &distance,
vector<int> &prevTop,
vector<int> &time,
vector<char> &topColor) {
stack<pair<int, int> > S;
S.push(make_pair(start, -1));
topColor[start] = 'g';
currentTime++;
distance[start] = currentTime;
while (S.size()) {
int v = S.top().first;
int u = S.top().second;
int w = -1;
for (int i = 0; i < G[v].size(); i++)
if (G[v][i] != u && topColor[G[v][i]] == 'w') {
w = G[v][i];
break;
}
if (w == -1) {
S.pop();
topColor[v] = 'b';
currentTime++;
time[v] = currentTime;
}
else {
S.top().second = w;
if (topColor[w] == 'w') {
prevTop[w] = v;
S.push(make_pair(w, -1));
currentTime++;
distance[w] = currentTime;
topColor[w] = 'g';
}
}
}
return;
}
Заключение
С алгоритмом поиска в глубину разобрались, в ширину тоже, осталось решить задачки с помощью него. О них я подробнее написал в статье «Задачи, решаемые с помощью обхода в глубину графа». А на сегодня у меня все, спасибо за внимание!