You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -219,151 +219,223 @@ \section{Обход графа в ширину}
219
219
Данный алгоритм является основой для многих алгоритмов поиска в графе.
220
220
221
221
В общих чертах, задача заключается в том, чтобы начиная с некоторой заданной вершины графа (источника) обойти все достижимые из неё вершины в некотором порядке.
222
-
Шаг~--- просмотр все смежных.
223
-
И так для всего фронта.
224
-
Главное не посещать одну и ту же вершину несколько раз.
225
-
226
-
Псевдокод классического алгоритма
222
+
Обход в ширину решает эту задачу и задаёт порядок посещения вершин с использованием \emph{фронта обхода} (или просто \emph{фронта}).
223
+
\begin{definition}[Фронт обхода]
224
+
\emph{Фронт обхода} графа $\mbfscrG = \langle V, E, L \rangle$~--- это вектор размера $|V|$, содержащий информацию%
225
+
\sidenote{В самом простом случае это будет будев вектор $F$ такой, что $F[i] = \textit{true}$ тогда и только тогда, когда $i$ достижима из стартовой вершины за заданное число шагов.}
226
+
о вершинах графа, достижимых из стартовой ровно за $k$ шагов для заданного $k$.
227
+
Иными словами, все вершины, информация о которых есть во фронте, достижимы из стартовой вершины за одинаковое число шагов.
228
+
\end{definition}
227
229
228
-
Пример.
230
+
Один шаг алгоритма заключается в рассмотрении всех вершин, смежных со всеми вершинами текущего фронта и формировании из него нового фронта.
231
+
При формировании нового фронта необходимо учесть, что в процессе обхода не нужно посещать одну и ту же вершину несколько раз%
232
+
\sidenote{Как правило не нужно.
233
+
Существуют алгоритмы, использующие аналогичную конструкцию с фронтом, но посещающие некоторые вершины несколько раз.
234
+
Например, поиск кратчайших путей от заданной вершины.}.
235
+
Схематичное изображение такого шага приведено на рисунке~\ref{fig:bfs_schema}.
236
+
\begin{marginfigure}
237
+
\begin{tikzpicture}
238
+
\begin{scope}
239
+
\node [circle, draw] (p1) {};
240
+
\node [text width=0.1cm] (p2) [below = 0.3 of p1] {$\vdots$};
241
+
\node [circle, draw] (p3) [below = 0.3 of p2] {};
242
+
\node [text width=0.1cm] (p4) [below = 0.3 of p3] {$\vdots$};
Алгоритм обхода в ширину может быть переформулирован в терминах матрично-векторных операций следующим образом%
231
276
\sidenote{
232
-
Стоит отметить, что ситуация с не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: на момент написания текста не известно естественного выражения данного обхода в терминах линейной алгебры.
277
+
Стоит отметить, что ситуация с не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: на момент написания текста не известно <<естественного>> выражения данного обхода в терминах линейной алгебры.
233
278
Доказательство невозможности такого построения также не предъявлены.
234
279
При этом, решения для частных случаев (деревья, ориентированные графы без циклов) предложены, например, в работе~\cite{10.1145/3315454.3329962}.}.
235
280
Пусть фронт~--- вектор размера $n$, а сам граф представлен матрицей смежности.
236
-
Тогда один шаг~--- получение нового фронта~--- это умножение текущего фронта на матрицу смежности.
237
-
Для того, чтобы отслеживать посещённые вершины нужна маска.
281
+
Тогда один шаг~--- просмотр всех смежных вершин для формирования нового нового фронта~--- это умножение текущего фронта на матрицу смежности.
282
+
Для того, чтобы отслеживать уже посещённые вершины, поддерживается булев вектор \emph{visited} размера $|V|$, такой, что $\emph{visited}[i] = \emph{true}$ тогда и только тогда, когда $i$ уже посещалась в процессе обхода.
283
+
Данный вектор используется как маска для фильтрации кандидатов в новый фронт.
238
284
239
285
Псевдокод алгоритма на ЛА
240
286
241
287
\begin{example}
242
288
243
-
Рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершины 2.
244
-
Для обозначения текущего фронта будем использовать зелёный цвет, а для достижимых из него за один шаг~--- жёлтый, обведём вершину красным, если она посешается повторно.
245
-
\marginnote{TODO: Как по мне, так надо просто написать каждый шаг словами, и тогда станет сильно проще сверстать}
Рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершины \circled{2}.
290
+
Для обозначения текущего фронта будем использовать зелёный цвет, а для достижимых из него за один шаг~--- жёлтый, обведём вершину красным, если она посещается повторно.
291
+
292
+
В начальном состоянии посещённых вершин нет и во фронте отмечена только вторая вершина (так как она является стартовой):
293
+
\begin{align*}
294
+
\emph{current\_front} & =
339
295
\begin{pmatrix}
340
296
0 & 0 & 1 & 0
341
297
\end{pmatrix}
342
-
$
343
-
\end{tabular}
298
+
\\
299
+
\emph{visited} & =
300
+
\begin{pmatrix}
301
+
0 & 0 & 0 & 0
302
+
\end{pmatrix}.
303
+
\end{align*}
304
+
305
+
Умножим фронт на матрицу смежности для того, чтобы выяснить, в какие вершины мы можем перейти из стартовой, и получить новый фронт:
306
+
\begin{align*}
307
+
\emph{new\_front} & = \emph{current\_front} \cdot M \\
308
+
& =
309
+
\begin{pmatrix}
310
+
0 & 0 & 1 & 0
311
+
\end{pmatrix}
312
+
\begin{pmatrix}
313
+
0 & 1 & 0 & 0 \\
314
+
0 & 0 & 1 & 0 \\
315
+
1 & 0 & 0 & 1 \\
316
+
0 & 0 & 1 & 0
317
+
\end{pmatrix} \\
318
+
& =
319
+
\begin{pmatrix}
320
+
1 & 0 & 0 & 1
321
+
\end{pmatrix}.
322
+
\end{align*}
323
+
324
+
Теперь вершину \circled{2} можно отметить как посещённую и создать фронт для следующей итерации с учётом нового фронта и посещённых вершин:
multiple-source BFS. Тот же обход в ширину, только источников несколько и надо помнить, какая из вершин из какого источника достижима. Постановка задачи. Решение через линейную алгебру~\sidecite{9286186} Уже не вектор, а матрица: храним информацию про каждую стартовую вершину отдельно.
408
+
Часто возникает необходимость совершить обход графа независимо из нескольких вершин.
409
+
При этом для каждой посещённой вершины необходимо знать, из какой именно стартовой вершины она достижима~\sidenote{Именно поэтому мы не можем сложить все стартовые вершины в один фронт.}.
410
+
Данную вариацию обхода будем называть обходом в ширину с несколькими стартовыми вершинами (multiple-source BFS, MS-BFS).
411
+
Для такой постановки задачи также предложен алгоритм, основанный на линейной алгебре~\sidecite{9286186}.
412
+
Идея его такая же, как у рассмотренного выше, однако фронт~--- это уже не вектор, а матрица размера $k \times |V|$, где $k$~--- количество стартовых вершин, каждая строка которой является фронтом для одной из стартовых вершин.
349
413
350
414
Псевдокод алгоритма на ЛА
351
415
352
-
Пример.
353
-
354
-
\begin{minipage}[c]{0.35\textwidth}
355
-
\input{figures/graph/graph_MS-BFS_1.tex}
356
-
\end{minipage}
357
-
\begin{minipage}{0.7\textwidth}
358
-
\end{minipage}
416
+
\begin{example}
417
+
Рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершин \circled{1} и \circled{3}.
0 commit comments