Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions doc/Paragraph_1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<font size = 3>

### 1.1. Ориентированный граф, псевдограф. Неориентированный граф, псевдограф. Связность в неор. графе, компоненты связности. Слабая и сильная связность в ор. графе. Компоненты слабой, сильной связности.
$\textbf{1.1.1 Граф}$ - упорядоченная пара $G$($V$, $E$), где $V$ - множество вершин, а $E$ $\subset$ ($V$ x $V$) - ребра. \
\
$\textbf{1.1.2 Ориентированный граф}$ - граф, в котором у каждого ребра есть направление, то есть стартовая и конечная вершины. \
\
$\textbf{1.1.3 Мультиграф}$ - граф, в котором хотя бы одна пара вершин соединена более чем одним ребром. \
\
$\textbf{1.1.4 Псевдограф}$ Псевдограф - мультиграф, в котором есть петли. \
\
$\textbf{1.1.5}$ Две вершины $u$ и $v$ **достижимы**, если найдется такая цепь из вершин $v$, $v_1$, $v_2$, ..., $v_n$, $u$, что $v_i$ смежна с $v_{i+1}$, а также смежны $v$, $v_1$ и $v_n$, $u$. \
\
$\textbf{1.1.6}$ Неориентированный граф **связен**, если для любой вершины все остальные достижимы из нее.\
\
$\textbf{1.1.7 Компонента связности в графе}$ - множество вершин графа достижимых попарно и рёбра их связывающие.\
\
$\textbf{1.1.8 Слабая связность в ориентированном графе}$ - ориентированный граф не связен, но его неориентированная копия связна.\
\
$\textbf{1.1.9 Сильная связность в оринетированном графе}$ - достижимость из произвольной вершины графа в любую другую.\
\
$\textbf{1.1.10 Компонента сильной связности в графе G}$ - подграф $G'$, который сильно связан.\
\
$\textbf{1.1.11 Компонента слабой связности в графе G}$ - подграф $G'$, который слабо связан. \
### 1.2. Обход в глубину. Цвета вершин. Времена входа и выхода. Лемма о белых путях(с доказательством).
\
$\textbf{1.2.1 Обход в глубину (DFS)}$ - это рекурсивный алгоритм по поиску всех вершин графа или дерева. Обход подразумевает под собой посещение всех вершин графа.\
\
$\quad$ **Алгоритм:** \
$\quad$ $\quad$ $1.$ Выбираем любую вершину $v$ из еще не посещенных. \
$\quad$ $\quad$ $2.$ Помечаем ее как пройденную. \
$\quad$ $\quad$ $3.$ Повторяем первые два шага к смежным к $v$ вершинам. \
\
$\textbf{1.2.2 Цвета вершин в DFS}$ \
$\quad$ **Белый** - вершина еще не была посещена. \
$\quad$ **Серый** - вершина в процессе обхода. \
$\quad$ **Черный** - вершина, у которой посещены все смежные ей вершины. \
\
$\textbf{1.2.3 Времена входа и выхода в DFS}$ - назовем временами входа и выхода пару чисел $entry[u], leave[u]$. Массивы $leave$ и $entry$ будем заполнять в ходе модифицированного DFS. \
\
$\textbf{1.2.4 Модифицированный DFS.}$
\
$\quad$ **Алгоритм:** \
$\quad$ $\quad$ $1.$ Все вершины в начале алгоритма белые. \
$\quad$ $\quad$ $2.$ Заводим переменную $time = $ 0. \
$\quad$ $\quad$ $3.$ Выберем произвольную вершину $u$, $entry[u] = time$. \
$\quad$ $\quad$ $4.$ Красим вершину $u$ в серый цвет, инкрементируем $time$. \
$\quad$ $\quad$ $5.$ Для каждой белой вершины, смежной с $u$, запускаем DFS. \
$\quad$ $\quad$ $6.$ Красим $u$ в черный цвет, инкременитруем $time$, $leave[u] = time$. \
\
$\textbf{1.2.5 Лемма о белых путях.}$ \
$\quad$ Пусть дан граф $G$. Запустим DFS($G$). Остановим выполнение процедуры DFS от какой-то вершины $u$ в тот момент, когда вершина $u$ была выкрашена в серый цвет (назовем первым моментом времени). Заметим, что в данный момент в графе $G$ есть как белые, так и черные и серые вершины. Продолжим выполнение процедуры DFS($u$) до того момента, когда вершина $u$ станет черной (второй момент времени). Тогда вершины графа $G$ \ {$u$}, бывшие черными и серыми в первый момент времени, не поменяют свой цвет ко второму моменту времени, а белые вершины либо останутся белыми, либо станут черными, причем черными станут те, что были достижимы от вершины $u$ по белым путям. \

**Доказательство:** \
$\quad$ Черные вершины останутся черными, потому что цвет может меняться только
по схеме белый, серый, черный. Серые останутся серыми, потому что они лежат в стеке рекурсии и
там и останутся. \
\
$\quad$ Заметим, что не существует такого момента в процессе обхода, что существует ребро из черной $v$
вершины в белую $u$. Действительно, запустим DFS($v$). В этот момент $v$ стала серой, а 𝑢 была белой.
Далее будет запущен DFS($u$), так как $u$ была белой. По алгоритму вершина $v$ будет покрашена в
черный цвет тогда, когда завершится обход всех вершин, достижимых из нее по одному ребру, кроме
тех, что были рассмотрены раньше нее. Таким образом, вершина $v$ может стать черной только тогда,
когда DFS выйдет из вершины $u$, и она будет покрашена в черный цвет. Получаем противоречие. \
\
$\quad$ Теперь заметим, что если вершина достижима по пути из белых вершин в первый момент времени,
то она стала черной ко сторому моменту времени (из абзаца выше следует).
Заметим, что это верно и в обратную сторону. Рассмотрим момент, когда вершина $v$ стала черной:
в этот момент существует cерый путь из $u$ в $v$, а это значит, что в первый момент времени сущестовал
белый путь из $u$ в $v$. \
\
$\quad$ Отсюда следует, что если вершина была перекрашена из белой в черную, то она была достижима
по белому пути, и что если вершина как была, так и осталась белой, она не была достижима по
белому пути, что и требовалось доказать. \
### 1.3. Проверка связности неориентированного графа. Поиск цикла в неориентированном и ориентированном графе. Топологическая сортировка.
$\textbf{1.3.1 Проверка связности ориентированного графа.}$ - модифицируем DFS так, чтобы он возвращал число посещенных вершин. Тогда запустим его от произвольной вершины, и если возвращенное число равно числу вершин в графе, то граф связный. \
\
$\textbf{1.3.2 Поиск цикла в неориентированном и ориентированном графе.}$ \
$\quad$ Будем решать задачу с помощью поиска в глубину. \
\
$\quad$ В случае ориентированного графа произведём серию обходов. То есть из каждой вершины, в
которую мы ещё ни разу не приходили, запустим поиск в глубину, который при входе в вершину
будет красить её в серый цвет, а при выходе из нее — в чёрный. И, если алгоритм пытается пойти в
серую вершину, то это означает, что цикл найден. \
\
$\quad$ В случае неориентированного графа, одно ребро не должно встречаться в цикле дважды по определению. Поэтому необходимо дополнительно проверять, что текущее рассматриваемое из вершины
ребро не является тем ребром, по которому мы пришли в эту вершину. \
\
$\textbf{1.3.3 Топологическая сортировка.}$ \
$\quad$ Топологическая сортировка ориентированного ациклического графа $G(V, E)$ представляет собой
упорядочивание вершин таким образом, что для любого ребра ($u$, $v$) $\in$ $E$ номер вершины 𝑢 меньше
номера вершины $u$. \
\
$\quad$ Предположим, что граф ацикличен, т.е. решение существует. Что делает обход в глубину? При
запуске из какой-то вершины $v$ он пытается запуститься вдоль всех рёбер, исходящих из $v$. Вдоль
тех рёбер, концы которых уже были посещены ранее, он не проходит, а вдоль всех остальных —
проходит и вызывает себя от их концов. \
\
$\quad$ Таким образом, к моменту выхода из вызова DFS($v$) все вершины, достижимые из $v$ как непосредственно (по одному ребру), так и косвенно (по пути)— все такие вершины уже посещены обходом. Следовательно, если мы будем в момент выхода из DFS($v$) добавлять нашу вершину в начало некоего списка, то в конце концов в этом списке получится топологическая сортировка. \
### 1.4. Нахождение компонент сильной связности. Алгоритм Косарайю. Алгоритм Тарьяна.
\
$\textbf{1.4.1 нахождение компонент сильной связности. Алгоритм Косарайю}$ \
$\quad$ **Алгоритм :** \
$\quad$ $\quad$ $1.$ Строим граф $H$ на основе данного графа $G$, инвертируя все ребра. \
$\quad$ $\quad$ $2.$ Запускаем DFS на этом графе, вычисляющий для каждой вершины время выхода DFS из нее. Пусть эти данные будут находиться в массиве $outTime$. \
$\quad$ $\quad$ $3.$ Выполняем DFS на исходном графе, перебирая вершины в порядке убывания $outTime[u]$. \
\
Подробнее про работу алгоритма рассказывается в этом видео: https://www.youtube.com/watch?v=-UgiBh1IMQU&t=704s \
\

Binary file added doc/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 19 additions & 1 deletion task_01/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>

int main() { return 0; }
#include "topology_sort.hpp"

int main() {
int n, m;
std::cin >> n >> m;

std::vector<std::vector<int> > graph;
graph.resize(n);
int tmp_from, tmp_to;
for (int i = 0; i < m; ++i) {
std::cin >> tmp_from >> tmp_to;
graph[tmp_from].push_back(tmp_to);
}

std::vector<int> vec = top_sort(graph);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'vec' of type 'std::vector' can be declared 'const' [misc-const-correctness]

Suggested change
std::vector<int> vec = top_sort(graph);
std::vector<int> const vec = top_sort(graph);

}
36 changes: 35 additions & 1 deletion task_01/src/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,39 @@
#include "topology_sort.hpp"

TEST(TopologySort, Simple) {
ASSERT_EQ(1, 1); // Stack []
std::vector<std::vector<int>> graph = {{2, 5, 4}, {3, 5, 6}, {}, {2},
{}, {2, 3, 4}, {3}, {5}};
std::vector<int> ans = {7, 1, 6, 0, 5, 4, 3, 2};
ASSERT_EQ(top_sort(graph), ans);
}

TEST(TopologySort, Cycle) {
std::vector<std::vector<int>> graph = {{1}, {2}, {0, 1, 2}, {}};
std::vector<int> ans = {3, 0, 1, 2};
ASSERT_EQ(top_sort(graph), ans);
}

TEST(TopologySort, Empty_graph) {
std::vector<std::vector<int>> graph = {{0}};
std::vector<int> ans = {0};
ASSERT_EQ(top_sort(graph), ans);
}

TEST(TopologySort, Full_graph_with_loops) {
std::vector<std::vector<int>> graph = {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}};
std::vector<int> ans = {0, 1, 2};
ASSERT_EQ(top_sort(graph), ans);
}

TEST(TopologySort, BIK_graph) {
std::vector<std::vector<int>> graph = {{1, 2, 3}, {5}, {5}, {4, 5}, {6, 8},
{4, 6, 7}, {9}, {9}, {7, 9}, {}};
std::vector<int> ans = {0, 3, 2, 1, 5, 4, 8, 7, 6, 9};
ASSERT_EQ(top_sort(graph), ans);
}

TEST(TopologySort, Isolated_verticles) {
std::vector<std::vector<int>> graph = {{1, 2, 3}, {0}, {1}, {2}, {}, {4}};
std::vector<int> res = {5, 4, 0, 3, 2, 1};
ASSERT_EQ(top_sort(graph), res);
}
27 changes: 27 additions & 0 deletions task_01/src/topology_sort.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
#include "topology_sort.hpp"

#include <algorithm>

void dfs(int v, std::vector<bool> &used, std::vector<int> &result,
std::vector<std::vector<int> > &graph) {
used[v] = true;
for (int i = 0; i < graph[v].size(); ++i) {
int to = graph[v][i];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'to' of type 'int' can be declared 'const' [misc-const-correctness]

Suggested change
int to = graph[v][i];
int const to = graph[v][i];

if (!used[to]) dfs(to, used, result, graph);
}

result.push_back(v);
}

std::vector<int> top_sort(std::vector<std::vector<int> > &graph) {
std::vector<bool> used;
used.resize(graph.size());

std::vector<int> result;
for (int i = 0; i < graph.size(); ++i) {
if (!used[i]) dfs(i, used, result, graph);
}

reverse(result.begin(), result.end());

return result;
}
6 changes: 6 additions & 0 deletions task_01/src/topology_sort.hpp
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
#pragma once
#include <vector>

void dfs(int v, std::vector<bool> &used, std::vector<int> &result,
std::vector<std::vector<int> > &graph);

std::vector<int> top_sort(std::vector<std::vector<int> > &graph);
25 changes: 25 additions & 0 deletions task_02/src/AllFunc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "AllFunc.hpp"

void AllFunc(std::vector<std::vector<int> > &graph,
std::set<std::pair<int, int> > &result, std::set<int> &cpvector) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: parameter 'cpvector' is unused [misc-unused-parameters]

Suggested change
std::set<std::pair<int, int> > &result, std::set<int> &cpvector) {
std::set<std::pair<int, int> > &result, std::set<int> & /*cpvector*/) {

int timer = 0, parent = -1;

std::vector<int> tin(graph.size(), 0);
std::vector<int> fup(graph.size(), 0);
std::vector<bool> used(graph.size(), 0);

std::set<std::pair<int, int> > res;

std::set<int> cpvec;

for (int i = 0; i < graph.size(); i++) {
if (!used[i]) {
FindBridges(timer, i, graph, tin, fup, parent, res, used);
}
}
result = returnBridges(res);
tin.resize(graph.size(), 0);
fup.resize(graph.size(), 0);
used.resize(graph.size(), 0);
FindCutPoint(timer, 0, graph, tin, fup, parent, cpvec, used);
}
7 changes: 7 additions & 0 deletions task_02/src/AllFunc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "FindBridges.hpp"
#include "FindCutPoints.hpp"

void AllFunc(std::vector<std::vector<int> > &graph,
std::set<std::pair<int, int> > &result, std::set<int> &cpvector);
27 changes: 27 additions & 0 deletions task_02/src/FindBridges.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "FindBridges.hpp"

void FindBridges(int &timer, int start, std::vector<std::vector<int> > &graph,
std::vector<int> &tin, std::vector<int> &fup, int parent,
std::set<std::pair<int, int> > &result,
std::vector<bool> used) {
used[start] = 1;
tin[start] = fup[start] = ++timer;
int to;
for (int i = 0; i < graph[start].size(); ++i) {
to = graph[start][i];
if (to == parent) continue;
if (used[to])
fup[start] = std::min(fup[start], tin[to]);
else {
FindBridges(timer, to, graph, tin, fup, start, result, used);
fup[start] = std::min(fup[start], fup[to]);
if (fup[to] > tin[start])
result.insert({std::min(start, to), std::max(start, to)});
}
}
}

std::set<std::pair<int, int> > returnBridges(
std::set<std::pair<int, int> > &result) {
return result;
}
14 changes: 14 additions & 0 deletions task_02/src/FindBridges.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <iostream>
#include <set>
#include <utility>
#include <vector>

void FindBridges(int &timer, int start, std::vector<std::vector<int> > &graph,
std::vector<int> &tin, std::vector<int> &fup, int parent,
std::set<std::pair<int, int> > &result,
std::vector<bool> used);

std::set<std::pair<int, int> > returnBridges(
std::set<std::pair<int, int> > &result);
24 changes: 24 additions & 0 deletions task_02/src/FindCutPoints.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "FindCutPoints.hpp"

void FindCutPoint(int &timer, int start, std::vector<std::vector<int> > &graph,
std::vector<int> &tin, std::vector<int> &fup, int parent,
std::set<int> &cpvec, std::vector<bool> used) {
used[start] = 1;
tin[start] = fup[start] = ++timer;
int to;
int children = 0;
for (int i = 0; i < graph[start].size(); ++i) {
to = graph[start][i];
if (to == parent) continue;
if (used[to])
fup[start] = std::min(fup[start], tin[to]);
else {
FindCutPoint(timer, to, graph, tin, fup, start, cpvec, used);
fup[start] = std::min(fup[start], fup[to]);
if (fup[to] >= tin[start] && parent != -1) cpvec.insert(start);
children++;
}
}
}

std::set<int> returnCP(std::set<int> &cpvec) { return cpvec; }
12 changes: 12 additions & 0 deletions task_02/src/FindCutPoints.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <iostream>
#include <set>
#include <utility>
#include <vector>

void FindCutPoint(int &timer, int start, std::vector<std::vector<int> > &graph,
std::vector<int> &tin, std::vector<int> &fup, int parent,
std::set<int> &cpvec, std::vector<bool> used);

std::set<int> returnCP(std::set<int> &cpvec);
5 changes: 3 additions & 2 deletions task_02/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <iostream>
#include "FindBridges.hpp"
#include "FindCutPoints.hpp"

int main() { return 0; }
int main() {}
Loading