Skip to content

Commit bd07b50

Browse files
committed
Работаем над теорией графов.
1 parent f84b038 commit bd07b50

File tree

2 files changed

+196
-120
lines changed

2 files changed

+196
-120
lines changed

tex/FormalLanguageConstrainedReachabilityLectureNotes.tex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
\usepackage{caption}
2121
\usepackage{subcaption}
22+
\usetikzlibrary {backgrounds}
23+
24+
\newcommand*\circled[1]{\tikz[baseline=(char.base)]{
25+
\node[shape=circle,draw,inner sep=2pt] (char) {#1};}}
2226

2327
\pghyphenation[]{russian}{%
2428
тео-ре-ти-ко-мно-жест-вен-ных

tex/GraphTheoryIntro.tex

Lines changed: 192 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -219,151 +219,223 @@ \section{Обход графа в ширину}
219219
Данный алгоритм является основой для многих алгоритмов поиска в графе.
220220

221221
В общих чертах, задача заключается в том, чтобы начиная с некоторой заданной вершины графа (источника) обойти все достижимые из неё вершины в некотором порядке.
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}
227229

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$};
243+
\begin{pgfonlayer}{background}
244+
\path[fill=green,rounded corners]
245+
([yshift=5pt,xshift=-2pt] p1.north west) rectangle ([yshift=-5pt,xshift=2pt] p4.south east);
246+
\end{pgfonlayer}
247+
\end{scope}
248+
249+
\begin{scope}
250+
\node [circle, draw] (q1) [right = of p1] {};
251+
\node [text width=0.1cm] (q2) [below = 0.3 of q1] {$\vdots$};
252+
\node [circle, draw] (q3) [below = 0.3 of q2] {};
253+
\begin{pgfonlayer}{background}
254+
\path[fill=yellow,rounded corners]
255+
([yshift=5pt,xshift=-2pt] q1.north west) rectangle ([yshift=-5pt,xshift=2pt] q3.south east);
256+
\end{pgfonlayer}
257+
\end{scope}
258+
\node[text width=2.5cm] (new) [below right = 0.4 of q3] {\scriptsize{новый фронт}};
259+
\node[text width=2.5cm] (current) [below right = 0.1 of p4] {\scriptsize{текущий фронт}};
260+
261+
\path[->]
262+
(p1) edge (q1)
263+
(p1) edge (q3)
264+
(p3) edge (q3)
265+
(p2) edge (q2)
266+
(p4) edge (q2)
267+
(new) edge [dashed] ([yshift=-5pt,xshift=-2.5pt] q3.south east)
268+
(current) edge [dashed] ([yshift=2.5pt, xshift=0.5pt] p4.south east)
269+
;
270+
\end{tikzpicture}
271+
\caption{Схема одного шага обхода в ширину}
272+
\label{fig:bfs_schema}
273+
\end{marginfigure}
229274

230275
Алгоритм обхода в ширину может быть переформулирован в терминах матрично-векторных операций следующим образом%
231276
\sidenote{
232-
Стоит отметить, что ситуация с не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: на момент написания текста не известно естественного выражения данного обхода в терминах линейной алгебры.
277+
Стоит отметить, что ситуация с не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: на момент написания текста не известно <<естественного>> выражения данного обхода в терминах линейной алгебры.
233278
Доказательство невозможности такого построения также не предъявлены.
234279
При этом, решения для частных случаев (деревья, ориентированные графы без циклов) предложены, например, в работе~\cite{10.1145/3315454.3329962}.}.
235280
Пусть фронт~--- вектор размера $n$, а сам граф представлен матрицей смежности.
236-
Тогда один шаг~--- получение нового фронта~--- это умножение текущего фронта на матрицу смежности.
237-
Для того, чтобы отслеживать посещённые вершины нужна маска.
281+
Тогда один шаг~--- просмотр всех смежных вершин для формирования нового нового фронта~--- это умножение текущего фронта на матрицу смежности.
282+
Для того, чтобы отслеживать уже посещённые вершины, поддерживается булев вектор \emph{visited} размера $|V|$, такой, что $\emph{visited}[i] = \emph{true}$ тогда и только тогда, когда $i$ уже посещалась в процессе обхода.
283+
Данный вектор используется как маска для фильтрации кандидатов в новый фронт.
238284

239285
Псевдокод алгоритма на ЛА
240286

241287
\begin{example}
242288

243-
Рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершины 2.
244-
Для обозначения текущего фронта будем использовать зелёный цвет, а для достижимых из него за один шаг~--- жёлтый, обведём вершину красным, если она посешается повторно.
245-
\marginnote{TODO: Как по мне, так надо просто написать каждый шаг словами, и тогда станет сильно проще сверстать}
246-
\begin{tabular}[t]{c | c}
247-
\begin{minipage}[c]{0.35\textwidth}
248-
\input{figures/graph/graph_BFS_1.tex}
249-
\end{minipage}
250-
&
251-
\begin{minipage}{0.7\textwidth}
252-
$\begin{aligned}
253-
\emph{current\_front} & =
254-
\begin{pmatrix}
255-
0 & 0 & 1 & 0
256-
\end{pmatrix}
257-
\\
258-
\emph{visited} & =
259-
\begin{pmatrix}
260-
0 & 0 & 0 & 0
261-
\end{pmatrix}
262-
\\
263-
\emph{new\_front} & =
264-
\emph{current\_front} \cdot M
265-
\\
266-
& =
267-
\begin{pmatrix}
268-
0 & 0 & 1 & 0
269-
\end{pmatrix}
270-
\begin{pmatrix}
271-
0 & 1 & 0 & 0 \\
272-
0 & 0 & 1 & 0 \\
273-
1 & 0 & 0 & 1 \\
274-
0 & 0 & 1 & 0
275-
\end{pmatrix} \\
276-
& =
277-
\begin{pmatrix}
278-
1 & 0 & 0 & 1
279-
\end{pmatrix}
280-
\\
281-
\emph{visited} & = \emph{visited} \emph{new\_front} \\
282-
& =
283-
\begin{pmatrix}
284-
0 & 0 & 0 & 0
285-
\end{pmatrix}
286-
\begin{pmatrix}
287-
0 & 0 & 1 & 0
288-
\end{pmatrix}
289-
\\
290-
\emph{current\_front} & = \emph{visited} \emph{new\_front}
291-
\\
292-
& =
293-
\begin{pmatrix}
294-
1 & 0 & 0 & 1
295-
\end{pmatrix}
296-
\begin{pmatrix}
297-
0 & 0 & 1 & 0
298-
\end{pmatrix} \\
299-
& =
300-
\begin{pmatrix}
301-
1 & 0 & 0 & 1
302-
\end{pmatrix} \\
303-
\end{aligned}$
304-
\end{minipage}
305-
\\ \hline
306-
\begin{minipage}[c]{0.35\textwidth}
307-
\input{figures/graph/graph_BFS_2.tex}
308-
\end{minipage}
309-
&
310-
$\begin{aligned}
311-
& \begin{pmatrix}
312-
1 & 0 & 0 & 1
313-
\end{pmatrix}
314-
\begin{pmatrix}
315-
0 & 1 & 0 & 0 \\
316-
0 & 0 & 1 & 0 \\
317-
1 & 0 & 0 & 1 \\
318-
0 & 0 & 1 & 0
319-
\end{pmatrix} \\ &=
320-
\begin{pmatrix}
321-
0 & 1 & 1 & 0
322-
\end{pmatrix}
323-
\end{aligned}$
324-
\\ \hline
325-
\begin{minipage}[c]{0.35\textwidth}
326-
\input{figures/graph/graph_BFS_3.tex}
327-
\end{minipage}
328-
&
329-
$
330-
\begin{pmatrix}
331-
0 & 1 & 0 & 0
332-
\end{pmatrix}
333-
\begin{pmatrix}
334-
0 & 1 & 0 & 0 \\
335-
0 & 0 & 1 & 0 \\
336-
1 & 0 & 0 & 1 \\
337-
0 & 0 & 1 & 0
338-
\end{pmatrix} =
289+
Рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершины \circled{2}.
290+
Для обозначения текущего фронта будем использовать зелёный цвет, а для достижимых из него за один шаг~--- жёлтый, обведём вершину красным, если она посещается повторно.
291+
292+
В начальном состоянии посещённых вершин нет и во фронте отмечена только вторая вершина (так как она является стартовой):
293+
\begin{align*}
294+
\emph{current\_front} & =
339295
\begin{pmatrix}
340296
0 & 0 & 1 & 0
341297
\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} можно отметить как посещённую и создать фронт для следующей итерации с учётом нового фронта и посещённых вершин:
325+
\begin{align*}
326+
\emph{visited} & = \emph{visited} \emph{new\_front} \\
327+
& =
328+
\begin{pmatrix}
329+
0 & 0 & 0 & 0
330+
\end{pmatrix}
331+
\begin{pmatrix}
332+
0 & 0 & 1 & 0
333+
\end{pmatrix}
334+
\\
335+
\emph{current\_front} & = \emph{visited} \emph{new\_front}
336+
\\
337+
& =
338+
\begin{pmatrix}
339+
1 & 0 & 0 & 1
340+
\end{pmatrix}
341+
\begin{pmatrix}
342+
0 & 0 & 1 & 0
343+
\end{pmatrix} \\
344+
& =
345+
\begin{pmatrix}
346+
1 & 0 & 0 & 1
347+
\end{pmatrix}.
348+
\end{align*}
349+
350+
Состояние графа после первой итерации показано на рисунке~\ref{fig:bfs_step_1}.
351+
\begin{marginfigure}
352+
\begin{center}
353+
\scalebox{0.8}{\input{figures/graph/graph_BFS_1.tex}}
354+
\end{center}
355+
\caption{Обход в ширину, шаг первый}
356+
\label{fig:bfs_step_1}
357+
\end{marginfigure}
358+
359+
\begin{align*}
360+
& \begin{pmatrix}
361+
1 & 0 & 0 & 1
362+
\end{pmatrix}
363+
\begin{pmatrix}
364+
0 & 1 & 0 & 0 \\
365+
0 & 0 & 1 & 0 \\
366+
1 & 0 & 0 & 1 \\
367+
0 & 0 & 1 & 0
368+
\end{pmatrix} \\ &=
369+
\begin{pmatrix}
370+
0 & 1 & 1 & 0
371+
\end{pmatrix}
372+
\end{align*}
373+
374+
\begin{marginfigure}
375+
\begin{center}
376+
\scalebox{0.8}{\input{figures/graph/graph_BFS_2.tex}}
377+
\end{center}
378+
\caption{Обход в ширину, шаг второй}
379+
\label{fig:bfs_step_2}
380+
\end{marginfigure}
381+
382+
\begin{align*}
383+
\begin{pmatrix}
384+
0 & 1 & 0 & 0
385+
\end{pmatrix}
386+
\begin{pmatrix}
387+
0 & 1 & 0 & 0 \\
388+
0 & 0 & 1 & 0 \\
389+
1 & 0 & 0 & 1 \\
390+
0 & 0 & 1 & 0
391+
\end{pmatrix} =
392+
\begin{pmatrix}
393+
0 & 0 & 1 & 0
394+
\end{pmatrix}
395+
\end{align*}
396+
397+
\begin{marginfigure}
398+
\begin{center}
399+
\scalebox{0.8}{\input{figures/graph/graph_BFS_3.tex}}
400+
\end{center}
401+
\caption{Обход в ширину, шаг третий}
402+
\label{fig:bfs_step_3}
403+
\end{marginfigure}
344404

345405
\end{example}
346406

347407

348-
multiple-source BFS. Тот же обход в ширину, только источников несколько и надо помнить, какая из вершин из какого источника достижима. Постановка задачи. Решение через линейную алгебру~\sidecite{9286186} Уже не вектор, а матрица: храним информацию про каждую стартовую вершину отдельно.
408+
Часто возникает необходимость совершить обход графа независимо из нескольких вершин.
409+
При этом для каждой посещённой вершины необходимо знать, из какой именно стартовой вершины она достижима~\sidenote{Именно поэтому мы не можем сложить все стартовые вершины в один фронт.}.
410+
Данную вариацию обхода будем называть обходом в ширину с несколькими стартовыми вершинами (multiple-source BFS, MS-BFS).
411+
Для такой постановки задачи также предложен алгоритм, основанный на линейной алгебре~\sidecite{9286186}.
412+
Идея его такая же, как у рассмотренного выше, однако фронт~--- это уже не вектор, а матрица размера $k \times |V|$, где $k$~--- количество стартовых вершин, каждая строка которой является фронтом для одной из стартовых вершин.
349413

350414
Псевдокод алгоритма на ЛА
351415

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}.
359418

419+
Шаг 1~\ref{fig:ms_bfs_step_1}
420+
421+
\begin{marginfigure}
422+
\begin{center}
423+
\scalebox{0.8}{\input{figures/graph/graph_MS-BFS_1.tex}}
424+
\end{center}
425+
\caption{Обход в ширину с несколькими стартовыми вершинами, шаг первый}
426+
\label{fig:ms_bfs_step_1}
427+
\end{marginfigure}
360428

361-
\begin{minipage}[c]{0.35\textwidth}
362-
\input{figures/graph/graph_MS-BFS_2.tex}
363-
\end{minipage}
364-
\begin{minipage}{0.7\textwidth}
365-
\end{minipage}
429+
Шаг 2~\ref{fig:ms_bfs_step_2}
430+
\begin{marginfigure}
431+
\begin{center}
432+
\scalebox{0.8}{\input{figures/graph/graph_MS-BFS_2.tex}}
433+
\end{center}
434+
\caption{Обход в ширину с несколькими стартовыми вершинами, шаг второй}
435+
\label{fig:ms_bfs_step_2}
436+
\end{marginfigure}
366437

438+
\end{example}
367439

368440
\section{Задачи поиска путей}
369441

0 commit comments

Comments
 (0)