Skip to content

additional tasks by Krivoruchko Dmitry #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 82 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
9cfcf59
delete extra extension from docker
UmbrellaLeaf5 Sep 7, 2024
39f8a8f
update format CMakeLists
UmbrellaLeaf5 Sep 7, 2024
aa962ae
update lib folder
UmbrellaLeaf5 Sep 7, 2024
6e59658
update lib->utils name in CMakeLists
UmbrellaLeaf5 Sep 14, 2024
b5d47d1
Merge remote-tracking branch 'upstream/main'
UmbrellaLeaf5 Sep 21, 2024
ae45494
README beautify
UmbrellaLeaf5 Sep 21, 2024
6032727
add graph_additional_task
UmbrellaLeaf5 Sep 27, 2024
bcd54e5
docker file back
UmbrellaLeaf5 Sep 27, 2024
5230994
update edge.Name()
UmbrellaLeaf5 Sep 29, 2024
cf04922
update class Graph with unordered_map as AdjList
UmbrellaLeaf5 Sep 30, 2024
4c939f8
update names and comments
UmbrellaLeaf5 Sep 30, 2024
ff9397f
Merge remote-tracking branch 'upstream/main' into graph_additional_task
UmbrellaLeaf5 Oct 4, 2024
1ccac8e
CMakeLists hotfix
UmbrellaLeaf5 Oct 4, 2024
64008e7
Merge remote-tracking branch 'origin/graph_additional_task' into stro…
UmbrellaLeaf5 Oct 5, 2024
3976ff9
move graph to lib
UmbrellaLeaf5 Oct 5, 2024
04c762f
Merge remote-tracking branch 'upstream/main' into strongly_connected_…
UmbrellaLeaf5 Oct 5, 2024
b85a801
Merge remote-tracking branch 'upstream/main' into graph_additional_task
UmbrellaLeaf5 Oct 5, 2024
ffa9925
and const
UmbrellaLeaf5 Oct 6, 2024
4e8ea35
create folder
UmbrellaLeaf5 Oct 6, 2024
b9d5975
finish primary realization
UmbrellaLeaf5 Oct 7, 2024
c47cb73
fix mistakes
UmbrellaLeaf5 Oct 7, 2024
4fa263b
update README.md and add comments
UmbrellaLeaf5 Oct 7, 2024
8691cba
add tests
UmbrellaLeaf5 Oct 7, 2024
b224e5b
move graph class to lib
UmbrellaLeaf5 Oct 25, 2024
4ddb11c
create folder for dag_relaxation
UmbrellaLeaf5 Oct 25, 2024
6bfef24
add topological_sort from task_01
UmbrellaLeaf5 Oct 6, 2024
ffd686d
primary complete dag_relaxation
UmbrellaLeaf5 Oct 25, 2024
fb1cbba
add more exception throwing
UmbrellaLeaf5 Oct 25, 2024
0919619
code beautify
UmbrellaLeaf5 Oct 25, 2024
f737732
fix typo
UmbrellaLeaf5 Oct 25, 2024
05774f8
fix typo and add ContainsVert method in graph class
UmbrellaLeaf5 Oct 25, 2024
60b581a
fix typo and add ContainsVert method in graph class
UmbrellaLeaf5 Oct 25, 2024
6672c40
add ContainsVert method
UmbrellaLeaf5 Oct 25, 2024
60f10e7
code beautify
UmbrellaLeaf5 Oct 25, 2024
80637ba
add tests
UmbrellaLeaf5 Oct 26, 2024
a530c1f
update README.md
UmbrellaLeaf5 Oct 26, 2024
12dc12a
beautify concepts (move from constructor)
UmbrellaLeaf5 Oct 26, 2024
4000c47
beautify concepts (move from constructor) in graph class
UmbrellaLeaf5 Oct 26, 2024
b553558
beautify concepts (move from constructor) in graph class
UmbrellaLeaf5 Oct 26, 2024
729a22e
Merge remote-tracking branch 'upstream/main' into strongly_connected_…
UmbrellaLeaf5 Oct 27, 2024
664a7e5
Merge remote-tracking branch 'upstream/main' into dag_relaxation_addi…
UmbrellaLeaf5 Oct 27, 2024
cfc14c9
Merge remote-tracking branch 'upstream/main' into graph_additional_task
UmbrellaLeaf5 Oct 27, 2024
f1d3404
code beautify
UmbrellaLeaf5 Oct 27, 2024
6cb4ae5
code beautify
UmbrellaLeaf5 Oct 27, 2024
f01684b
code beautify
UmbrellaLeaf5 Oct 27, 2024
dd17ff5
change static funcs to anonymous namespace
UmbrellaLeaf5 Oct 27, 2024
19cffc6
update CMakeLists.txt
UmbrellaLeaf5 Oct 29, 2024
f4321ff
update CMakeLists.txt
UmbrellaLeaf5 Oct 29, 2024
01b22c8
update CMakeLists.txt
UmbrellaLeaf5 Oct 29, 2024
5dee1f6
change static funcs to anonymous namespace
UmbrellaLeaf5 Oct 30, 2024
650045a
code beautify
UmbrellaLeaf5 Oct 30, 2024
d40c1bd
code beautify
UmbrellaLeaf5 Oct 30, 2024
903be8b
fix tests
UmbrellaLeaf5 Nov 16, 2024
16f71c5
update task using Petya and Vasya scary maze problem
UmbrellaLeaf5 Nov 17, 2024
1f3015b
update tests and README.md
UmbrellaLeaf5 Nov 17, 2024
8cdba58
update task using chemical experiments problem
UmbrellaLeaf5 Nov 18, 2024
e252cdf
move graph class to lib
UmbrellaLeaf5 Oct 25, 2024
2382a0d
Merge branch 'strongly_connected_components_additional_task' into add…
UmbrellaLeaf5 Nov 23, 2024
ce2993f
Merge branch 'dag_relaxation_additional_task' into additional_tasks
UmbrellaLeaf5 Nov 23, 2024
609b741
rename algorithms folders to tasks names
UmbrellaLeaf5 Nov 23, 2024
7a14ed6
rename: start_vert -> start in DAGRelaxation
UmbrellaLeaf5 Nov 25, 2024
380efe7
add AStar primary realization
UmbrellaLeaf5 Nov 25, 2024
c87ebc8
optimize AStar: remove non_visited_verts
UmbrellaLeaf5 Nov 25, 2024
c2b29aa
code beautify
UmbrellaLeaf5 Nov 25, 2024
b7fda02
update comments
UmbrellaLeaf5 Nov 25, 2024
5a1efed
add GoodSolution and its maze parsing
UmbrellaLeaf5 Nov 25, 2024
5d4385a
update tests
UmbrellaLeaf5 Nov 25, 2024
b600b27
update README.md
UmbrellaLeaf5 Nov 25, 2024
a67d809
update comments in graph class and add move constructor
UmbrellaLeaf5 Nov 29, 2024
cbe81d7
update graph class: allow negative weight and add more template types
UmbrellaLeaf5 Nov 29, 2024
dfe0bfe
fix bugs in methods in class graph connected with undirected graph
UmbrellaLeaf5 Nov 29, 2024
e5fa95a
complete GitHub suggestions
UmbrellaLeaf5 Nov 29, 2024
1097fec
code beautify
UmbrellaLeaf5 Nov 29, 2024
fc5f0d2
rename: GetWeightOfEdge -> GetEdgeWeight, ParseEdgeString -> ParseEdg…
UmbrellaLeaf5 Dec 7, 2024
6d560f1
add graph class methods: GetEdgeIter, SetEdgeWeight
UmbrellaLeaf5 Dec 8, 2024
5761e70
move all methods in graph class to graph.hpp
UmbrellaLeaf5 Dec 8, 2024
efa50c7
move graph.hpp and utils.hpp to .. folder
UmbrellaLeaf5 Dec 8, 2024
fc3e316
update graph class (code simplify and beautify)
UmbrellaLeaf5 Dec 9, 2024
6e411db
update graph class (consts and integral->arithmetic)
UmbrellaLeaf5 Jan 13, 2025
07019ff
CMake structure update and code beautify
UmbrellaLeaf5 Jan 14, 2025
8afd94e
complete find_word_chains additional_task
UmbrellaLeaf5 Jan 15, 2025
2db05e3
complete bridge_guards additional_task
UmbrellaLeaf5 Jan 15, 2025
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
26 changes: 13 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.20)

project(homeworks)
project(homeworks LANGUAGES CXX)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -std=c++23 -O2")

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/sandbox)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/additional_tasks)

file(GLOB_RECURSE tasks_dirs LIST_DIRECTORIES true ".")
file(GLOB_RECURSE SUBFOLDERS LIST_DIRECTORIES true ".")

foreach(dir ${tasks_dirs})
IF(IS_DIRECTORY ${dir})
IF(${dir} MATCHES "task_0[0-9]$" AND NOT ${dir} MATCHES "build")
add_subdirectory(${dir})
ENDIF()
ELSE()
CONTINUE()
ENDIF()
foreach(FOLDER ${SUBFOLDERS})
if(IS_DIRECTORY ${FOLDER})
if(${FOLDER} MATCHES "task_0[0-9]$" AND NOT ${FOLDER} MATCHES "build")
add_subdirectory(${FOLDER})
endif()
endif()
endforeach()
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Домашнее задание для 2 семестра алгоритмов и структур данных
## (Homework for second semester algorithms and data structures on MIPT DAFE/RSE)

### Для удобства можно пользоваться папкой lib, все файлы из этой папки будут подключаться к любой задаче

### Можно получить дополнительные баллы, если добавить интересные текстовые задачи. Необходимы текст задачи, решение и тесты. Каждая задача отдельный ПР, полчуть дополнительные баллы можно только если пулл реквест замержен в основную ветку.
Можно получить дополнительные баллы, если добавить интересные текстовые задачи. Необходимы текст задачи, решение и тесты. Каждая задача отдельный - Pull Request, получить дополнительные баллы можно только если PR замерджен в основную ветку.

### Можно получить дополнительные баллы, если добавить теорию в папку doc. Делается в отдельном ПР, полчуть дополнительные баллы можно только если пулл реквест замержен в основную ветку.
Можно получить дополнительные баллы, если добавить теорию в папку doc. Делается в отдельном PR, только если PR замерджен в основную ветку.

### Код должен быть отформатирован clang-format'ом со стилем Google
Код должен быть отформатирован clang-format'ом со стилем Google.
20 changes: 9 additions & 11 deletions additional_tasks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.20)

project(additional_tasks)
project(additional_tasks LANGUAGES CXX)

file(GLOB_RECURSE tasks_dirs LIST_DIRECTORIES true ".")
file(GLOB_RECURSE SUBFOLDERS LIST_DIRECTORIES true ".")

foreach(dir ${tasks_dirs})
IF(IS_DIRECTORY ${dir})
IF(NOT ${dir} MATCHES ".*src.*")
add_subdirectory(${dir})
ENDIF()
ELSE()
CONTINUE()
ENDIF()
foreach(FOLDER ${SUBFOLDERS})
if(IS_DIRECTORY ${FOLDER})
if(NOT ${FOLDER} MATCHES ".*src.*")
add_subdirectory(${FOLDER})
endif()
endif()
endforeach()
39 changes: 39 additions & 0 deletions additional_tasks/bridge_guards/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
cmake_minimum_required(VERSION 3.20)

get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
project(${PROJECT_NAME} LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

file(GLOB_RECURSE SOURCE_LIST "src/*.cpp" "src/*.hpp")
file(GLOB_RECURSE MAIN_SOURCE_LIST "src/main.cpp")
set(TEST_SOURCE_LIST ${SOURCE_LIST})
file(GLOB_RECURSE test_list "src/*test.cpp")

list(REMOVE_ITEM TEST_SOURCE_LIST ${MAIN_SOURCE_LIST})
list(REMOVE_ITEM SOURCE_LIST ${test_list})

include_directories(${PROJECT_NAME} PUBLIC src)

find_library(Utils ../)

add_executable(${PROJECT_NAME} ${SOURCE_LIST})
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)

# Locate GTest
enable_testing()
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

# Link runTests with what we want to test and the GTest and pthread library
add_executable(${PROJECT_NAME}_tests ${TEST_SOURCE_LIST})
target_link_libraries(
${PROJECT_NAME}_tests
GTest::gtest_main
Utils
)

include(GoogleTest)
gtest_discover_tests(${PROJECT_NAME}_tests)
221 changes: 221 additions & 0 deletions additional_tasks/bridge_guards/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# Задача: охранники речных мостов

Река имеет `N` контрольно-пропускных пунктов на левом берегу и `M` контрольно-пропускных пунктов на правом берегу.

`P` мостов построены, соединяя контрольно-пропускные пункты через реку. На контрольно-пропускных пунктах необходимо разместить охрану, и охрана может защищать все мосты, на которых присутствует этот КПП.

Для защиты одного моста может быть более одного охранника.

Найдите минимальное количество охранников, необходимое для защиты всех мостов через реку.

## Входные данные:

* Первая строка ввода состоит из 2 целых чисел, разделенных пробелами `N`
и `M` − количество КПП на левом и правом берегу реки соответственно (1 ≤ `N`, `M` ≤ 100)
* Вторая строка ввода состоит из одного целого числа `P` − общее количество мостов через реку (1 ≤ `P` ≤ 100).
* Следующие `P` строк, каждая из которых состоит из 2 целых чисел, разделенных пробелами `u`, `v`, обозначающих, что между КПП `u` на левом берегу и КПП `v` на правом берегу есть мост (1 ≤ `u` ≤ `N`) (1 ≤ `v` ≤ `M`).

## Выходные данные:

* Одно целое число − минимальное количество охранников, необходимое для защиты всех мостов через реку.

## Пример:

### Вход:
```
4 3
4
1 3
1 2
2 2
4 1
```

### Выход:
```
3
```

### Решение:

#### Введение и моделирование графом:

Для решения задачи о часовых на реке, смоделируем ситуацию с помощью двудольного графа.
Одна доля графа представляла пункты наблюдения на левом берегу, а другая – на правом берегу.

Ребра между долями обозначали мосты. Целью было найти минимальный набор вершин (пунктов), которые ‘покрывают’ все ребра (мосты). Это классическая задача поиска минимального вершинного покрытия.

Известно, что в общем случае задача поиска минимального вершинного покрытия является NP-трудной, то есть не существует быстрого алгоритма для произвольных графов. Однако, для двудольных графов эту задачу можно решить за полиномиальное время, применив теорему Кёнига.

**Теорема Кёнига** утверждает, что в двудольном графе размер минимального вершинного покрытия равен размеру максимального паросочетания.

*Паросочетание* – это набор ребер, которые не имеют общих вершин, то есть ни одна вершина не является концом более чем одного ребра в паросочетании.

*Максимальное паросочетание* – это паросочетание с наибольшим возможным количеством ребер.

#### Максимальное паросочетание и алгоритм поиска максимального потока:

Для нахождения максимального паросочетания используем алгоритм поиска максимального потока.

Чтобы применить этот алгоритм, преобразуем двудольный граф в сеть, добавив искусственный источник (`s`) и сток (`t = s + 1`).

Источник (`s`) имел ребра единичной пропускной способности ко всем вершинам, представляющим пункты на левом берегу. Все вершины, представляющие пункты на правом берегу, имели ребра единичной пропускной способности к стоку (`t`). Рёбра между пунктами левого и правого берегов (представляющие мосты) также имели единичную пропускную способность.

Это преобразование позволило свести задачу поиска максимального паросочетания к задаче поиска максимального потока в созданной сети.

Для поиска максимального потока используем модификацию алгоритма Эдмондса-Карпа, реализуя обход в ширину (BFS) для поиска увеличивающего пути.

Функция `BFS` реализована следующим образом:
```C++
inline size_t BFS(size_t s, std::vector<ssize_t>& parent,
std::vector<std::vector<size_t>>& adj_list,
std::vector<std::vector<size_t>>& capacity) {
parent[s] = -2;
size_t n = parent.size();

std::vector<bool> visited(n, false);
visited[s] = true;

std::queue<std::pair<size_t, size_t>> nodes;

nodes.push({s, LLONG_MAX});

while (!nodes.empty()) {
std::pair<size_t, size_t> node_flow = nodes.front();
size_t node = node_flow.first;
size_t flow = node_flow.second;

nodes.pop();

for (size_t i = 0; i < adj_list[node].size(); i++) {
size_t next = adj_list[node][i];

if (visited[next] || capacity[node][i] == 0) continue;

visited[next] = true;

parent[next] = node;

size_t new_flow = std::min(flow, capacity[node][i]);

if (next == s + 1) return new_flow;
nodes.push({next, new_flow});
}
}

return 0;
}
```

В этой функции `parent` используется для отслеживания пути, `adj_list` - список смежности, `capacity` - матрица пропускных способностей. Функция возвращает пропускную способность найденного увеличивающего пути, или 0, если путь не найден.

#### Реализация алгоритма максимального потока:

Алгоритм максимального потока реализован в функции `MaxFlow`:
```C++
inline size_t MaxFlow(size_t s, std::vector<std::vector<size_t>>& adj_list,
std::vector<std::vector<size_t>>& capacity) {
size_t flow = 0;
std::vector<ssize_t> parent(adj_list.size(), -1);

size_t new_flow = 0;

while ((new_flow = BFS(s, parent, adj_list, capacity))) {
flow += new_flow;
size_t curr = s + 1;

while (curr != s) {
size_t prev = parent[curr];
size_t idx = (find(adj_list[prev].begin(), adj_list[prev].end(), curr) -
adj_list[prev].begin());
capacity[prev][idx] -= new_flow;

idx = (find(adj_list[curr].begin(), adj_list[curr].end(), prev) -
adj_list[curr].begin());
capacity[curr][idx] += new_flow;

curr = prev;
}
}

return flow;
}

```

Функция `MaxFlow` инициализирует поток в 0, и пока находит увеличивающие пути с помощью `BFS`, наращивает поток и обновляет пропускные способности остаточных ребер. Возвращает величину максимального потока.

#### Преобразование двудольного графа в сеть и нахождение максимального паросочетания

Преобразование двудольного графа в сеть и использование алгоритма максимального потока для нахождения максимального паросочетания реализовано в функции `MaximumBipartiteMatching`:
```C++
inline size_t MaximumBipartiteMatching(size_t n, size_t m,
Graph<size_t>& bipartite_graph) {
std::vector<std::vector<std::pair<size_t, size_t>>> bipartite_edges_stack(
n + m + 3);
std::vector<std::vector<size_t>> adj_list(n + m + 3);
std::vector<std::vector<size_t>> capacity(n + m + 3);

for (size_t i = 0; i < bipartite_graph.EdgesAmount(); i++) {
size_t u = StartVertFromTuple(bipartite_graph.Edges()[i]);
size_t v = EndVertFromTuple(bipartite_graph.Edges()[i]);

v += n;

bipartite_edges_stack[u].push_back({v, 1});
bipartite_edges_stack[v].push_back({u, 0});
}

for (size_t i = 1; i <= n; i++) {
bipartite_edges_stack[n + m + 1].push_back({i, 1});
bipartite_edges_stack[i].push_back({n + m + 1, 0});
}
for (size_t i = 1; i <= m; i++) {
bipartite_edges_stack[i + n].push_back({n + m + 2, 1});
bipartite_edges_stack[n + m + 2].push_back({i + n, 0});
}

for (size_t i = 1; i <= n + m + 2; i++)
sort(bipartite_edges_stack[i].begin(), bipartite_edges_stack[i].end());

for (size_t i = 1; i <= n + m + 2; i++)
for (size_t j = 0; j < bipartite_edges_stack[i].size(); j++) {
adj_list[i].push_back(bipartite_edges_stack[i][j].first);
capacity[i].push_back(bipartite_edges_stack[i][j].second);
}

return MaxFlow(n + m + 1, adj_list, capacity);
}

```

В этой функции двудольный граф `bipartite_graph` преобразуется в сеть с помощью `bipartite_edges_stack`, добавляется источник (`n + m + 1`) и сток (`n + m + 2`), затем строится матрица смежности `adj_list` и матрица пропускных способностей `capacity` и вызывается функция MaxFlow для вычисления максимального потока.

#### Вызов функции решения и заключение:

Функция `Solution` считывает входные данные и выводит результат:

```C++
inline void Solution(std::istream& is = std::cin,
std::ostream& os = std::cout) {
size_t n, m;
is >> n >> m;

size_t p;
is >> p;

Graph<size_t> bipartite_graph;

for (size_t i = 0; i < p; i++) {
size_t u, v;
is >> u >> v;

bipartite_graph.AddEdge({u, v});
}

os << MaximumBipartiteMatching(n, m, bipartite_graph) << std::endl;
return;
}
```

В результате, величина максимального потока, возвращаемая функцией `MaximumBipartiteMatching` и являющаяся размером максимального паросочетания, дает размер минимального вершинного покрытия, что и являлось ответом к задаче – минимальное количество необходимых часовых.
Loading