diff --git a/lib/src/graph.h b/lib/src/graph.h new file mode 100644 index 0000000..47e6ed7 --- /dev/null +++ b/lib/src/graph.h @@ -0,0 +1,70 @@ +#ifndef GRAPH_H_ +#define GRAPH_H_ + +#include +#include + +class Graph { + struct vert_neigh { + int name; + double lenght; + + vert_neigh(int name, double lenght) : name{name}, lenght{lenght} {} + vert_neigh(std::pair p) : name{p.first}, lenght{p.second} {} + }; + + public: + // { {0, 1}, {1, 0}, {2, 3}, {2, 4}, {2, 5} } + Graph(int verts_num, std::initializer_list> links) { + adjacents = std::vector>(verts_num, + std::vector()); + for (auto pair : links) { + adjacents[pair.first].push_back(vert_neigh(pair.second, 1.)); + } + } + + // { {{0, 1}, lenght1}, {{1, 0}, lenght2}, ... } + Graph(int verts_num, + std::initializer_list, double>> links) { + adjacents = std::vector>(verts_num, + std::vector()); + for (auto pair : links) { + adjacents[pair.first.first].push_back( + vert_neigh(pair.first.second, pair.second)); + } + } + + int size() const { return adjacents.size(); } + + void add_vert() { adjacents.push_back({}); } + + friend std::ostream& operator<<(std::ostream& os, const Graph& g) { + os << " { "; + for (int i = 0; i < g.adjacents.size(); ++i) { + for (auto p : g.adjacents[i]) { + os << "{ {" << i << ", " << p.name << "}, " << p.lenght; + os << "}, "; + } + } + os << "}"; + return os; + } + + void see_vertical() { + int vert_name = -1; + for (auto vert : adjacents) { + vert_name++; + if (vert.size() == 0) { + std::cout << vert_name << std::endl; + continue; + } + for (auto link_to : vert) { + std::cout << vert_name << " -> " << link_to.name + << ", lenght:" << link_to.lenght << std::endl; + } + } + } + std::vector> adjacents; +}; + +#endif diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..cb8f649 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,242 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "topology_sort.hpp" + +bool is_sorted(Graph& g, std::vector& order) { + for (int i = 0; i < order.size(); ++i) { + for (int j = i + 1; j < order.size(); ++j) { + for (auto child : g.adjacents[order[j]]) { + if (child.name == order[i]) { + return false; + } + } + } + } + return true; +} + +TEST(non_recursive_topological_sort, Test_1) { + Graph g(8, { + {{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + }); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_non_rec(g)), true); +} + +TEST(non_recursive_topological_sort, Test_2) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{2, 3}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_non_rec(g)), true); +} + +TEST(non_recursive_topological_sort, Test_3) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{2, 3}, 1}, + {{1, 2}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_non_rec(g)), true); +} + +TEST(non_recursive_topological_sort, Test_4) { + Graph g(9, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{8, 0}, 1}, + {{0, 5}, 1}, + {{5, 6}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_non_rec(g)), true); +} + +TEST(non_recursive_topological_sort, Test_cycles_1) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{5, 2}, 1}}); + + bool error_occured = false; + + try { + topological_sort_dfs_non_rec(g); + } catch (std::runtime_error) { + error_occured = true; + } + + ASSERT_EQ(error_occured, true); +} + +TEST(non_recursive_topological_sort, Test_cycles_2) { + Graph g(9, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{6, 8}, 1}, + {{4, 8}, 1}, + {{8, 3}, 1}}); + + bool error_occured = false; + + try { + topological_sort_dfs_non_rec(g); + } catch (std::runtime_error) { + error_occured = true; + } + + ASSERT_EQ(error_occured, true); +} + +TEST(recursive_topological_sort, Test_1) { + Graph g(8, { + {{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + }); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_rec(g)), true); +} + +TEST(recursive_topological_sort, Test_2) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{2, 3}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_rec(g)), true); +} + +TEST(recursive_topological_sort, Test_3) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{2, 3}, 1}, + {{1, 2}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_rec(g)), true); +} + +TEST(recursive_topological_sort, Test_4) { + Graph g(9, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{8, 0}, 1}, + {{0, 5}, 1}, + {{5, 6}, 1}}); + + ASSERT_EQ(is_sorted(g, *topological_sort_dfs_rec(g)), true); +} + +TEST(recursive_topological_sort, Test_cycles_1) { + Graph g(8, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{5, 2}, 1}}); + + bool error_occured = false; + + try { + topological_sort_dfs_rec(g); + } catch (std::runtime_error) { + error_occured = true; + } + + ASSERT_EQ(error_occured, true); +} + +TEST(recursive_topological_sort, Test_cycles_2) { + Graph g(9, {{{1, 4}, 4}, + {{1, 6}, 5}, + {{2, 7}, 9}, + {{3, 4}, 1}, + {{3, 7}, 5.5}, + {{4, 5}, 3.14}, + {{7, 0}, 0.2}, + {{7, 5}, 1.3}, + {{7, 6}, 2.6}, + {{6, 8}, 1}, + {{4, 8}, 1}, + {{8, 3}, 1}}); + + bool error_occured = false; + + try { + topological_sort_dfs_rec(g); + } catch (std::runtime_error) { + error_occured = true; + } + + ASSERT_EQ(error_occured, true); } \ No newline at end of file diff --git a/task_01/src/topology_sort.cpp b/task_01/src/topology_sort.cpp new file mode 100644 index 0000000..6fb0f68 --- /dev/null +++ b/task_01/src/topology_sort.cpp @@ -0,0 +1,123 @@ +#include "topology_sort.hpp" + +#include + +void dfs_mark_non_rec(Graph& g, std::vector& marks, + std::vector& visited, int start_name) { + std::stack st; + st.push(start_name); + + while (!st.empty()) { + int const v = st.top(); + + if (visited[v] == 2) { + st.pop(); + for (int i = 0; i < marks.size(); ++i) { + if (marks[marks.size() - 1 - i] == -1) { + marks[marks.size() - 1 - i] = v; + break; + } + } + visited[v] = 3; + continue; + } else if (visited[v] == 3) { + st.pop(); + continue; + } + + visited[v] = 1; + + int finished_children = 0; + for (auto child : g.adjacents[v]) { + if (visited[child.name] == 1) { + throw std::runtime_error("Graph contains cycle!"); + } else if (visited[child.name] == 0) { + st.push(child.name); + } else { + finished_children++; + } + } + + if (finished_children == g.adjacents[v].size()) { + visited[v] = 2; + } + } +} + +std::vector* topological_sort_dfs_non_rec(Graph& g) { + if (g.size() == 0) { + return new std::vector(); + } + + std::vector visited( + g.size(), + 0); // 0 not started verticle , 1 started verticle, 2 - finished + // verticle, 3 - added and finished verticle + std::vector* sorted = new std::vector(g.size(), -1); + + bool calculated; + for (int i = 0; i < visited.size(); ++i) { + calculated = true; + for (int j = 0; j < visited.size(); ++j) { + if (visited[j] == 0) { + calculated = false; + dfs_mark_non_rec(g, *sorted, visited, j); + break; + } + } + if (calculated) { + break; + }; + } + + return sorted; +} + +void dfs_mark_rec(Graph& g, std::vector& marks, std::vector& visited, + int vert) { + visited[vert] = 1; + + for (auto child : g.adjacents[vert]) { + if (visited[child.name] == 1) { + throw std::runtime_error("Graph contains cycle!"); + } else if (visited[child.name] == 0) { + dfs_mark_rec(g, marks, visited, child.name); + } + } + + visited[vert] = 2; + for (int i = 0; i < marks.size(); ++i) { + if (marks[marks.size() - 1 - i] == -1) { + marks[marks.size() - 1 - i] = vert; + break; + } + } +} + +std::vector* topological_sort_dfs_rec(Graph& g) { + if (g.size() == 0) { + return new std::vector(); + } + + std::vector visited(g.size(), + 0); // 0 not started verticle , 1 started verticle , + // 2 - finished verticle + std::vector* sorted = new std::vector(g.size(), -1); + + bool calculated; + for (int i = 0; i < visited.size(); ++i) { + calculated = true; + for (int j = 0; j < visited.size(); ++j) { + if (visited[j] == 0) { + calculated = false; + dfs_mark_rec(g, *sorted, visited, j); + break; + } + } + if (calculated) { + break; + }; + } + + return sorted; +} \ No newline at end of file diff --git a/task_01/src/topology_sort.hpp b/task_01/src/topology_sort.hpp new file mode 100644 index 0000000..4e64b33 --- /dev/null +++ b/task_01/src/topology_sort.hpp @@ -0,0 +1,18 @@ +#ifndef TOPOLOGY_SORT_H_ +#define TOPOLOGY_SORT_H_ + +#include + +#include "../../lib/src/graph.h" + +void dfs_mark_non_rec(Graph& g, std::vector& marks, + std::vector& visited, int start_name); + +std::vector* topological_sort_dfs_non_rec(Graph& g); + +void dfs_mark_rec(Graph& g, std::vector& marks, std::vector& visited, + int vert); + +std::vector* topological_sort_dfs_rec(Graph& g); + +#endif \ No newline at end of file diff --git a/task_02/src/find_bridges_cut_verts.cpp b/task_02/src/find_bridges_cut_verts.cpp new file mode 100644 index 0000000..3df75f1 --- /dev/null +++ b/task_02/src/find_bridges_cut_verts.cpp @@ -0,0 +1,140 @@ +#include "find_bridges_cut_verts.hpp" + +#include + +bool dfs_path_to_vert_exist(Graph& g, std::vector& path_visited, + std::pair& deleted_edge, int vert, + int target) { + path_visited[vert] = 1; + for (auto child : g.adjacents[vert]) { + if (child.name == target && + (std::pair({vert, child.name}) != deleted_edge)) { + return true; + } + if (path_visited[child.name] != 0 || + (std::pair({vert, child.name}) == deleted_edge)) { + continue; + } + if (dfs_path_to_vert_exist(g, path_visited, deleted_edge, child.name, + target)) { + return true; + } + } + path_visited[vert] = 2; + return false; +} + +void dfs_check_edges_rec(Graph& g, std::vector& visited, + std::vector>& bridges, int vert) { + visited[vert] = 1; + + for (auto child : g.adjacents[vert]) { + std::vector path_visited(g.size(), 0); + std::pair deleted_edge({child.name, vert}); + if (visited[child.name] != 1 && + (std::find(bridges.begin(), bridges.end(), + std::pair({vert, child.name})) == bridges.end()) && + (std::find(bridges.begin(), bridges.end(), + std::pair({child.name, vert})) == bridges.end())) { + if (!dfs_path_to_vert_exist(g, path_visited, deleted_edge, child.name, + vert)) { + bridges.push_back({vert, child.name}); + } + dfs_check_edges_rec(g, visited, bridges, child.name); + } + } + + visited[vert] = 2; +} + +std::vector> get_bridges(Graph& g) { + std::vector visited(g.size(), 0); + std::vector> bridges; + + bool all_verts_calculated; + for (int i = 0; i < g.size(); ++i) { + all_verts_calculated = true; + for (int j = 0; j < g.size(); ++j) { + if (visited[j] == 0) { + all_verts_calculated = false; + dfs_check_edges_rec(g, visited, bridges, j); + } + } + if (all_verts_calculated) { + break; + } + } + return bridges; +} + +void dfs_taryan(Graph& g, std::vector& visited, std::vector& tin, + std::vector& fup, + std::vector>& bridges, int time, int v, + int p = -1) { + visited[v] = true; + tin[v] = fup[v] = time++; + for (size_t i = 0; i < g.adjacents[v].size(); ++i) { + int const to = g.adjacents[v][i].name; + if (to == p) continue; + if (visited[to]) + fup[v] = std::min(fup[v], tin[to]); + else { + dfs_taryan(g, visited, tin, fup, bridges, time, to, v); + fup[v] = std::min(fup[v], fup[to]); + if (fup[to] > tin[v]) bridges.push_back(std::pair({v, to})); + } + } +} + +std::vector> get_bridges_taryan(Graph& g) { + int const time = 0; + std::vector tin(g.size(), -1); + std::vector fup(g.size(), -1); + std::vector> bridges; + + std::vector visited(g.size(), false); + for (int i = 0; i < g.size(); ++i) + if (!visited[i]) dfs_taryan(g, visited, tin, fup, bridges, time, i); + return bridges; +} + +void dfs_taryan_verts(Graph& g, std::vector& visited, + std::vector& tin, std::vector& fup, + std::vector& cut_verts, int time, int v, + int p = -1) { + visited[v] = true; + tin[v] = fup[v] = time++; + int count = 0; + for (auto child : g.adjacents[v]) { + if (child.name == p) { + continue; + } + if (visited[child.name]) { + fup[v] = std::min(fup[v], tin[child.name]); + } else { + dfs_taryan_verts(g, visited, tin, fup, cut_verts, time, child.name, v); + count++; + fup[v] = std::min(fup[v], fup[child.name]); + if (fup[child.name] >= tin[v] && p != -1) cut_verts.push_back(v); + } + } + + if (p == -1 && count >= 2) { + cut_verts.push_back(v); + } +} + +std::vector get_cut_verts_taryan(Graph& g) { + int const time = 0; + std::vector tin(g.size(), -1); + std::vector fup(g.size(), -1); + std::vector cut_verts; + + std::vector visited(g.size(), false); + for (int i = 1; i < g.size(); ++i) + if (!visited[i]) dfs_taryan_verts(g, visited, tin, fup, cut_verts, time, i); + std::sort(cut_verts.begin(), cut_verts.end()); + cut_verts.erase(std::unique(cut_verts.begin(), cut_verts.end()), + cut_verts.end()); + return cut_verts; +} \ No newline at end of file diff --git a/task_02/src/find_bridges_cut_verts.hpp b/task_02/src/find_bridges_cut_verts.hpp new file mode 100644 index 0000000..cd0e3f7 --- /dev/null +++ b/task_02/src/find_bridges_cut_verts.hpp @@ -0,0 +1,32 @@ +#ifndef FIND_BRIDGES_CUT_VERTS_H_ +#define FIND_BRIDGES_CUT_VERTS_H_ + +#include + +#include "../../lib/src/graph.h" + +bool dfs_path_to_vert_exist(Graph& g, std::vector& path_visited, + std::pair& deleted_edge, int vert, + int target); + +void dfs_check_edges_rec(Graph& g, std::vector& visited, + std::vector>& bridges, int vert); + +// my own algorithm +std::vector> get_bridges(Graph& g); + +void dfs_taryan(Graph& g, std::vector& visited, std::vector& tin, + std::vector& fup, + std::vector>& bridges, int time, int v, + int p); + +// taryan algorithm +std::vector> get_bridges_taryan(Graph& g); + +void dfs_taryan_verts(Graph& g, std::vector& visited, + std::vector& tin, std::vector& fup, + std::vector& cut_verts, int time, int v, int p); + +std::vector get_cut_verts_taryan(Graph& g); + +#endif \ No newline at end of file diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp deleted file mode 100644 index 8ca8990..0000000 --- a/task_02/src/stack.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "stack.hpp" - -#include - -void Stack::Push(int value) { data_.push(value); } - -int Stack::Pop() { - auto result = data_.top(); - data_.pop(); - return result; -} - -void MinStack::Push(int value) { data_.push_back(value); } - -int MinStack::Pop() { - auto result = data_.back(); - data_.pop_back(); - return result; -} - -int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); } \ No newline at end of file diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp deleted file mode 100644 index 138ec40..0000000 --- a/task_02/src/stack.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -class Stack { - public: - void Push(int value); - int Pop(); - - private: - std::stack data_; -}; - -class MinStack { - public: - void Push(int value); - int Pop(); - int GetMin(); - - private: - std::vector data_; -}; diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 54e7ce9..e30f9c5 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,42 +1,113 @@ #include -#include - -#include "stack.hpp" - -TEST(StackTest, Simple) { - Stack stack; - stack.Push(1); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - stack.Push(3); // Stack [1, 3] - ASSERT_EQ(stack.Pop(), 3); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] -} - -TEST(MinStackTest, Simple) { - MinStack stack; - stack.Push(1); // Stack [1] - ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - stack.Push(3); // Stack [1, 3] - ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 3); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] +#include + +#include "find_bridges_cut_verts.hpp" + +bool vector_int_equal(std::vector& v1, std::initializer_list& v2) { + if (v1.size() != v2.size()) { + return false; + } + + for (auto elem : v1) { + if (std::find(v2.begin(), v2.end(), elem) == v2.end()) { + return false; + } + } + return true; +} + +bool vector_pair_equal(std::vector>& v1, + std::initializer_list>& v2) { + if (v1.size() != v2.size()) { + return false; + } + + for (auto elem : v1) { + if (std::find(v2.begin(), v2.end(), elem) == v2.end() && + std::find(v2.begin(), v2.end(), + std::pair({elem.second, elem.first})) == v2.end()) { + return false; + } + } + return true; +} + +TEST(get_bridges, Test_1) { + Graph g(9, {{0, 1}, {0, 2}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {1, 6}, {2, 6}, + {3, 7}, {7, 8}, {4, 8}, {1, 0}, {2, 0}, {2, 1}, {3, 2}, {4, 3}, + {6, 5}, {6, 1}, {6, 2}, {7, 3}, {8, 7}, {8, 4}}); + std::vector> bridges = get_bridges(g); + std::initializer_list> true_bridges = {{2, 3}, {5, 6}}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_bridges_taryan, Test_1) { + Graph g(9, {{0, 1}, {0, 2}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {1, 6}, {2, 6}, + {3, 7}, {7, 8}, {4, 8}, {1, 0}, {2, 0}, {2, 1}, {3, 2}, {4, 3}, + {6, 5}, {6, 1}, {6, 2}, {7, 3}, {8, 7}, {8, 4}}); + std::vector> bridges = get_bridges_taryan(g); + std::initializer_list> true_bridges = {{2, 3}, {5, 6}}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_cut_verts_taryan, Test_1) { + Graph g(9, {{0, 1}, {0, 2}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {1, 6}, {2, 6}, + {3, 7}, {7, 8}, {4, 8}, {1, 0}, {2, 0}, {2, 1}, {3, 2}, {4, 3}, + {6, 5}, {6, 1}, {6, 2}, {7, 3}, {8, 7}, {8, 4}}); + std::vector bridges = get_cut_verts_taryan(g); + std::initializer_list true_bridges = {2, 3, 6}; + + ASSERT_EQ(vector_int_equal(bridges, true_bridges), true); +} + +TEST(get_bridges, Test_2) { + Graph g(3, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}}); + std::vector> bridges = get_bridges(g); + std::initializer_list> true_bridges = {}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_bridges_taryan, Test_2) { + Graph g(3, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}}); + std::vector> bridges = get_bridges_taryan(g); + std::initializer_list> true_bridges = {}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_cut_verts_taryan, Test_2) { + Graph g(3, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}}); + std::vector bridges = get_cut_verts_taryan(g); + std::initializer_list true_bridges = {}; + + ASSERT_EQ(vector_int_equal(bridges, true_bridges), true); +} + +TEST(get_bridges, Test_3) { + Graph g(4, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}, {0, 3}, {3, 0}}); + std::vector> bridges = get_bridges(g); + std::initializer_list> true_bridges = {{0, 3}}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_bridges_taryan, Test_3) { + Graph g(4, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}, {0, 3}, {3, 0}}); + std::vector> bridges = get_bridges_taryan(g); + std::initializer_list> true_bridges = {{0, 3}}; + + ASSERT_EQ(vector_pair_equal(bridges, true_bridges), true); +} + +TEST(get_cut_verts_taryan, Test_3) { + Graph g(4, {{0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 2}, {2, 1}, {0, 3}, {3, 0}}); + std::vector bridges = get_cut_verts_taryan(g); + std::initializer_list true_bridges = {0}; + + ASSERT_EQ(vector_int_equal(bridges, true_bridges), true); } \ No newline at end of file diff --git a/task_03/src/johnson.cpp b/task_03/src/johnson.cpp new file mode 100644 index 0000000..28bffa9 --- /dev/null +++ b/task_03/src/johnson.cpp @@ -0,0 +1,76 @@ +#include "johnson.hpp" + +#include +#include + +void dfs_mark_rec(Graph& g, std::vector& marks, std::vector& visited, + int vert) { + visited[vert] = 1; + + for (auto child : g.adjacents[vert]) { + if (visited[child.name] == 0) { + dfs_mark_rec(g, marks, visited, child.name); + } + } + + visited[vert] = 2; + for (int i = 0; i < marks.size(); ++i) { + if (marks[marks.size() - 1 - i] == -1) { + marks[marks.size() - 1 - i] = vert; + break; + } + } +} + +std::vector* topological_sort_dfs_rec(Graph& g) { + if (g.size() == 0) { + return new std::vector(); + } + + std::vector visited(g.size(), + 0); // 0 not started verticle , 1 started verticle , + // 2 - finished verticle + std::vector* sorted = new std::vector(g.size(), -1); + + bool calculated; + for (int i = 0; i < visited.size(); ++i) { + calculated = true; + for (int j = 0; j < visited.size(); ++j) { + if (visited[j] == 0) { + calculated = false; + dfs_mark_rec(g, *sorted, visited, j); + break; + } + } + if (calculated) { + break; + }; + } + + return sorted; +} + +std::vector belllman_ford(Graph& g, int start_vert) { + std::vector dists(g.size(), std::numeric_limits::max()); + std::vector const top_order = *topological_sort_dfs_rec(g); + dists[start_vert] = 0; + + for (int i = 0; i < g.size() - 1; ++i) { + for (int const v : top_order) { + for (auto child : g.adjacents[v]) { + if (dists[v] > dists[child.name] + child.lenght) { + dists[v] = dists[child.name] + child.lenght; + } + } + } + } + + for (int const v : top_order) { + for (auto child : g.adjacents[v]) { + if (dists[start_vert] > dists[child.name] + child.lenght) { + throw std::runtime_error("Graph contains negative cycles!"); + } + } + } + return dists; +} \ No newline at end of file diff --git a/task_03/src/johnson.hpp b/task_03/src/johnson.hpp new file mode 100644 index 0000000..a7d7b78 --- /dev/null +++ b/task_03/src/johnson.hpp @@ -0,0 +1,13 @@ +#ifndef JOHNSON_H_ +#define JOHNSON_H_ + +#include "../../lib/src/graph.h" + +std::vector* topological_sort_dfs_rec(Graph& g); + +void dfs_mark_rec(Graph& g, std::vector& marks, std::vector& visited, + int vert); + +std::vector belllman_ford(Graph& g, int start_vert); + +#endif \ No newline at end of file diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..5e11617 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,6 @@ #include -#include "topology_sort.hpp" - TEST(TopologySort, Simple) { ASSERT_EQ(1, 1); // Stack [] } diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp deleted file mode 100644 index e53f670..0000000 --- a/task_03/src/topology_sort.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "topology_sort.hpp" diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/task_03/src/topology_sort.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/task_04/src/dijkstra.cpp b/task_04/src/dijkstra.cpp new file mode 100644 index 0000000..0a6157f --- /dev/null +++ b/task_04/src/dijkstra.cpp @@ -0,0 +1,36 @@ +#include "dijkstra.hpp" + +#include +#include + +std::map dijkstra(Graph& g, int start_vert) { + std::map dists; + std::vector finished(g.size(), false); + + for (int i = 0; i < g.size(); ++i) { + dists[i] = std::numeric_limits::infinity(); + } + dists[start_vert] = 0; + finished[start_vert] = true; + + int active_vert = start_vert; + double min_lenght = std::numeric_limits::infinity(); + for (int i = 0; i < g.size() - 1; ++i) { + for (auto child : g.adjacents[active_vert]) { + if (dists[child.name] > child.lenght + dists[active_vert]) { + dists[child.name] = child.lenght + dists[active_vert]; + } + } + + min_lenght = std::numeric_limits::infinity(); + for (int j = 0; j < g.size(); j++) { + if (!finished[j] && (dists[j] < min_lenght)) { + min_lenght = dists[j]; + active_vert = j; + } + } + finished[active_vert] = true; + } + + return dists; +} diff --git a/task_04/src/dijkstra.hpp b/task_04/src/dijkstra.hpp new file mode 100644 index 0000000..9faec87 --- /dev/null +++ b/task_04/src/dijkstra.hpp @@ -0,0 +1,9 @@ +#ifndef DIJKSTRA_H_ +#define DIJKSTRA_H_ + +#include + +#include "../../lib/src/graph.h" + +std::map dijkstra(Graph& g, int start_vert); +#endif \ No newline at end of file diff --git a/task_04/src/main.cpp b/task_04/src/main.cpp index 0e4393b..76e8197 100644 --- a/task_04/src/main.cpp +++ b/task_04/src/main.cpp @@ -1,3 +1 @@ -#include - int main() { return 0; } diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..43bf465 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,235 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "dijkstra.hpp" + +TEST(unorient_graph, Test_1) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 0}, {1, 7}, {2, 9}, {3, 20}, {4, 20}, {5, 11}}) == + dijkstra(g, 0)); + + ASSERT_EQ(passed, true); } + +TEST(unorient_graph, Test_2) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 7}, {1, 0}, {2, 10}, {3, 15}, {4, 21}, {5, 12}}) == + dijkstra(g, 1)); + + ASSERT_EQ(passed, true); +} + +TEST(unorient_graph, Test_3) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 9}, {1, 10}, {2, 0}, {3, 11}, {4, 11}, {5, 2}}) == + dijkstra(g, 2)); + + ASSERT_EQ(passed, true); +} + +TEST(unorient_graph, Test_4) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 20}, {1, 15}, {2, 11}, {3, 0}, {4, 6}, {5, 13}}) == + dijkstra(g, 3)); + + ASSERT_EQ(passed, true); +} + +TEST(unorient_graph, Test_5) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 20}, {1, 21}, {2, 11}, {3, 6}, {4, 0}, {5, 9}}) == + dijkstra(g, 4)); + + ASSERT_EQ(passed, true); +} + +TEST(unorient_graph, Test_6) { + Graph g(6, { + {{0, 1}, 7}, + {{1, 0}, 7}, + {{0, 2}, 9}, + {{2, 0}, 9}, + {{1, 2}, 10}, + {{2, 1}, 10}, + {{0, 5}, 14}, + {{5, 0}, 14}, + {{2, 5}, 2}, + {{5, 2}, 2}, + {{2, 3}, 11}, + {{3, 2}, 11}, + {{1, 3}, 15}, + {{3, 1}, 15}, + {{3, 4}, 6}, + {{4, 3}, 6}, + {{5, 4}, 9}, + {{4, 5}, 9}, + }); + bool const passed = + (std::map( + {{0, 11}, {1, 12}, {2, 2}, {3, 13}, {4, 9}, {5, 0}}) == + dijkstra(g, 5)); + + ASSERT_EQ(passed, true); +} + +TEST(orient_graph, Test_1) { + Graph g(5, { + {{1, 0}, 34}, + {{0, 2}, 6}, + {{2, 0}, 7}, + {{2, 1}, 23}, + {{3, 1}, 29}, + {{1, 4}, 37}, + {{0, 4}, 25}, + {{0, 3}, 122}, + {{4, 2}, 11}, + }); + bool const passed = + (std::map({{0, 0}, {1, 29}, {2, 6}, {3, 122}, {4, 25}}) == + dijkstra(g, 0)); + + ASSERT_EQ(passed, true); +} + +TEST(orient_graph, Test_2) { + Graph g(5, { + {{1, 0}, 34}, + {{0, 2}, 6}, + {{2, 0}, 7}, + {{2, 1}, 23}, + {{3, 1}, 29}, + {{1, 4}, 37}, + {{0, 4}, 25}, + {{0, 3}, 122}, + {{4, 2}, 11}, + }); + bool const passed = + (std::map({{0, 34}, {1, 0}, {2, 40}, {3, 156}, {4, 37}}) == + dijkstra(g, 1)); + + ASSERT_EQ(passed, true); +} + +TEST(orient_graph, Test_3) { + Graph g(5, { + {{1, 0}, 34}, + {{0, 2}, 6}, + {{2, 0}, 7}, + {{2, 1}, 23}, + {{3, 1}, 29}, + {{1, 4}, 37}, + {{0, 4}, 25}, + {{0, 3}, 122}, + {{4, 2}, 11}, + }); + bool const passed = + (std::map({{0, 63}, {1, 29}, {2, 69}, {3, 0}, {4, 66}}) == + dijkstra(g, 3)); + + ASSERT_EQ(passed, true); +} \ No newline at end of file diff --git a/task_05/src/rmq.cpp b/task_05/src/rmq.cpp new file mode 100644 index 0000000..4de14be --- /dev/null +++ b/task_05/src/rmq.cpp @@ -0,0 +1,36 @@ +#include "rmq.hpp" + +#include +#include +#include + +RMQ::RMQ(std::vector data) { + sparse_table = std::vector>( + std::log2(data.size()) + 1, + std::vector(data.size(), + std::numeric_limits::infinity())); + int wide; + auto start = data.end(); + auto end = data.begin(); + for (int i = 0; i < sparse_table.size(); ++i) { + for (int j = data.size() - 1; j >= 0; --j) { + wide = (1 << i); + end = data.begin() + j + 1; + start = end - wide; + if (start >= data.begin()) { + sparse_table[i][j] = *std::min_element(start, end); + } + } + } +} + +double RMQ::get_min(int first_ind, int last_ind) { + int const smaller_log = std::floor(std::log2(last_ind - first_ind + 1)); + if (std::pow(2, smaller_log) == (last_ind - first_ind + 1)) { + return sparse_table[smaller_log][last_ind]; + } + + return std::min( + sparse_table[smaller_log][first_ind + std::pow(2, smaller_log) - 1], + sparse_table[smaller_log][last_ind]); +} diff --git a/task_05/src/rmq.hpp b/task_05/src/rmq.hpp new file mode 100644 index 0000000..165315f --- /dev/null +++ b/task_05/src/rmq.hpp @@ -0,0 +1,23 @@ +#ifndef RMQ_H_ +#define RMQ_H_ + +#include + +#include + +std::vector> rmq_sparse_table(std::vector& data); + +double get_min_from_sparse_table(std::vector>& sparse_table, + int start_ind, int end_ind); + +class RMQ { + public: + RMQ(std::vector data); + + double get_min(int first_ind, int last_ind); + + private: + std::vector> sparse_table; +}; + +#endif \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..9728404 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,124 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "rmq.hpp" + +TEST(sparse_table_get_min, Test_1) { + std::vector data({1, 5, 8, 6, 7, 4, 3, 2}); + RMQ rmq(data); + + for (int i = 0; i < data.size(); ++i) { + for (int j = i; j < data.size(); ++j) { + ASSERT_EQ(rmq.get_min(i, j), + *std::min_element(data.begin() + i, data.begin() + j + 1)); + } + } } + +TEST(get_min, Test_1) { + std::vector data({3, 8, 6, 4, 2, 5, 9, 0, 7, 1}); + RMQ rmq(data); + + for (int i = 0; i < data.size(); ++i) { + for (int j = i; j < data.size(); ++j) { + ASSERT_EQ(rmq.get_min(i, j), + *std::min_element(data.begin() + i, data.begin() + j + 1)); + } + } +} + +TEST(get_min_big_array, Test_1) { + std::vector data( + {1681, 2743, 349, 2296, 29, 1964, 1128, 3849, 1758, 1638, 1341, 32, + 2745, 1257, 2654, 439, 1649, 2583, 2910, 2070, 2886, 1286, 1611, 807, + 2857, 2039, 715, 1635, 1167, 3474, 1733, 932, 1385, 1267, 3985, 3445, + 1305, 606, 3658, 1100, 3374, 1155, 2838, 1924, 605, 1620, 2956, 3077, + 1536, 2730, 2957, 994, 2959, 1082, 3349, 1435, 1971, 2284, 2916, 1407, + 1255, 3775, 2433, 787, 855, 211, 1565, 1228, 215, 3313, 989, 2753, + 1125, 2885, 1764, 2655, 2062, 3228, 336, 1269, 167, 2717, 84, 2016, + 2958, 3812, 891, 3814, 3041, 2979, 2467, 3645, 2421, 2375, 3612, 3678, + 1686, 2274, 1727, 2188, 1885, 2170, 790, 1226, 1030, 1981, 2380, 2308, + 834, 3510, 308, 1342, 3677, 2331, 2472, 3586, 972, 2621, 3224, 245, + 3379, 1716, 59, 3050, 448, 2090, 2476, 2334, 2900, 3428, 902, 1704, + 1130, 2558, 3195, 1763, 2216, 1468, 1247, 3831, 971, 3614, 877, 1605, + 3571, 1904, 3309, 918, 995, 642, 3980, 2197, 3444, 392, 2064, 3611, + 3102, 747, 201, 2009, 2096, 2514, 2330, 3263, 1377, 3281, 1140, 3059, + 3590, 1601, 216, 3122, 2128, 2232, 2302, 481, 1503, 117, 474, 551, + 2775, 255, 1302, 905, 484, 1006, 525, 6, 1475, 3285, 3700, 3370, + 1862, 3635, 2081, 3964, 3359, 3984, 1906, 1262, 2818, 1564, 3624, 2315, + 3675, 2982, 3862, 1891, 1108, 3235, 621, 3711, 2922, 256, 472, 3010, + 1493, 1960, 2824, 3906, 2066, 156, 535, 3185, 1081, 2069, 1355, 2993, + 2011, 1025, 1303, 1312, 2635, 1708, 415, 3214, 3898, 1491, 1731, 136, + 2742, 1032, 2661, 1931, 816, 2109, 3596, 3748, 2883, 3151, 1951, 389, + 3954, 1244, 504, 1911, 1104, 69, 803, 717, 770, 1287, 1574, 3097, + 2021, 2735, 195, 1573, 3607, 2199, 610, 2205, 3314, 1111, 641, 370, + 2896, 3561, 100, 3629, 3650, 3808, 2249, 2499, 1331, 1301, 3803, 2728, + 592, 3708, 1847, 1728, 3125, 3267, 1569, 2174, 3948, 2050, 3690, 3483, + 2639, 2868, 699, 3794, 858, 1190, 461, 1893, 2304, 2488, 340, 3637, + 718, 1054, 964, 1908, 1804, 2492, 1440, 3996, 1399, 3566, 3867, 3918, + 79, 2147, 713, 3638, 1509, 3042, 3078, 2815, 2369, 1497, 1921, 1253, + 3391, 2531, 490, 914, 1289, 1446, 3509, 1988, 796, 1957, 50, 1735, + 2851, 2911, 3283, 1646, 266, 1023, 1766, 184, 111, 1641, 292, 1042, + 549, 3284, 3441, 1037, 409, 2914, 1252, 3575, 2028, 3315, 863, 442, + 2971, 2086, 455, 1444, 906, 680, 109, 2120, 1161, 2192, 3512, 1522, + 2477, 2666, 3361, 1403, 3599, 537, 3354, 3944, 2950, 810, 1428, 3525, + 1568, 449, 3627, 1320, 2122, 694, 3212, 554, 2548, 1437, 1103, 3356, + 900, 3219, 307, 483, 3194, 2276, 3462, 471, 1865, 3295, 3570, 2481, + 1853, 1651, 2707, 1665, 1518, 3095, 1158, 2527, 3527, 798, 2269, 3672, + 3239, 2354, 3572, 3115, 1076, 338, 3764, 3765, 1884, 2134, 2129, 2773, + 2312, 2874, 3076, 1003, 2054, 3615, 712, 355, 2569, 1598, 3583, 3738, + 2999, 2709, 3825, 3062, 2142, 3889, 2882, 695, 534, 865, 2381, 3182, + 2168, 3548, 811, 701, 1678, 497, 2486, 3273, 1627, 1271, 3369, 2949, + 1211, 829, 1984, 3494, 2752, 1548, 889, 2072, 3605, 3557, 919, 3795, + 808, 2051, 843, 574, 822, 3105, 91, 1720, 3238, 146, 2849, 306, + 626, 1927, 745, 779, 3994, 980, 3376, 572, 1109, 2300, 248, 3608, + 1237, 1322, 3640, 1292, 2314, 1337, 2057, 1892, 3377, 2336, 2863, 854, + 2223, 3234, 402, 424, 809, 1511, 2926, 922, 1089, 2892, 2913, 406, + 426, 3686, 3699, 3140, 2599, 1063, 2891, 301, 2107, 3934, 53, 1741, + 3935, 613, 3450, 1162, 947, 3005, 640, 65, 515, 3153, 2015, 2586, + 2894, 2719, 2565, 1754, 3770, 2511, 1369, 196, 1707, 2552, 1674, 1955, + 3656, 2547, 3542, 2608, 3191, 2410, 3768, 229, 1926, 2676, 1663, 1462, + 2278, 708, 2185, 1474, 2714, 3491, 3477, 3459, 7, 495, 1061, 2715, + 2788, 1531, 2614, 1599, 1220, 3163, 2604, 555, 3882, 1201, 2789, 3861, + 2259, 2796, 1756, 569, 503, 342, 969, 2759, 3517, 1263, 2002, 984, + 3697, 3793, 92, 3437, 3110, 3533, 586, 1526, 2036, 2320, 3835, 2865, + 774, 833, 304, 1624, 677, 841, 2361, 297, 1313, 1872, 2973, 3916, + 2215, 2053, 789, 1174, 2903, 1241, 1175, 443, 1464, 1819, 213, 645, + 1300, 2705, 801, 1633, 1655, 735, 1762, 533, 55, 3725, 1797, 679, + 1317, 974, 2450, 2038, 1845, 1534, 2221, 734, 3654, 477, 597, 1936, + 675, 2207, 3841, 2402, 3660, 1251, 371, 1644, 3329, 3207, 3471, 873, + 3995, 659, 1619, 527, 76, 73, 696, 3210, 888, 2750, 3482, 2522, + 750, 3885, 62, 352, 1024, 3232, 2180, 936, 3001, 436, 1552, 3123, + 3114, 3414, 1373, 3229, 3859, 3431, 2126, 2741, 926, 2087, 3009, 1864, + 3833, 3535, 3291, 730, 3582, 2990, 1041, 3903, 1266, 1547, 2132, 524, + 1077, 1656, 2518, 3362, 1351, 3134, 1485, 116, 33, 739, 1783, 379, + 2040, 1554, 2704, 2459, 3175, 1613, 1261, 979, 896, 2343, 3556, 3558, + 3201, 2394, 1680, 2585, 929, 520, 2596, 2563, 1223, 1356, 2855, 316, + 3897, 3446, 1993, 83, 3137, 1246, 1580, 3826, 2549, 2114, 37, 3338, + 3397, 1308, 3895, 3126, 852, 3250, 1932, 161, 2638, 2975, 2780, 3012, + 2737, 1688, 3341, 2915, 870, 1258, 1770, 3892, 231, 1382, 1260, 871, + 1306, 2112, 250, 2938, 1912, 1546, 1346, 1026, 2448, 3127, 3342, 3832, + 2253, 70, 3472, 118, 3956, 2754, 1172, 1495, 2840, 1587, 2852, 2699, + 2722, 2669, 714, 2373, 510, 2861, 1281, 2056, 2832, 2179, 1767, 3824, + 2637, 2426, 1593, 3755, 1873, 2755, 1411, 618, 777, 578, 303, 2769, + 417, 3745, 3839, 3716, 3960, 3967, 2035, 1119, 3392, 956, 2932, 1039, + 3111, 1829, 2245, 897, 2613, 825, 2927, 3206, 550, 365, 2869, 2200, + 746, 2751, 3343, 765, 3856, 742, 3519, 2322, 1422, 405, 3448, 1166, + 3776, 2363, 2508, 3691, 3260, 3619, 2046, 3673, 2805, 1004, 386, 3919, + 3737, 2316, 1530, 2677, 2540, 2523, 1642, 1771, 2291, 2566, 3215, 2018, + 656, 2440, 268, 1785, 2350, 2008, 1391, 1616, 2088, 1112, 1288, 1002, + 313, 3500, 828, 3930, 1349, 3757, 2209, 1153, 619, 1117, 3501, 2003, + 2898, 595, 1566, 3308, 1827, 1789, 3138, 1217, 1659, 2097, 219, 289, + 3193, 3758, 3317, 3636, 3879, 279, 3941, 743, 1183, 3368, 1050, 653, + 427, 2809, 851, 788, 2022, 775, 2266, 3301, 563, 310, 3616, 1939, + 1538, 3531, 1294, 1654, 2073, 2074, 139, 2995, 2151, 2942, 3049, 2734, + 1165, 3072, 293, 347}); + RMQ rmq(data); + + for (int i = 0; i < data.size(); ++i) { + for (int j = i; j < data.size(); ++j) { + ASSERT_EQ(rmq.get_min(i, j), + *std::min_element(data.begin() + i, data.begin() + j + 1)); + } + } +} \ No newline at end of file diff --git a/task_06/src/lca.cpp b/task_06/src/lca.cpp new file mode 100644 index 0000000..46a9e7c --- /dev/null +++ b/task_06/src/lca.cpp @@ -0,0 +1,50 @@ +#include "lca.hpp" + +#include + +LCA::LCA(const Graph& g, int root) { + const int height = std::floor(std::log2(g.size()) + 1); + sparse_table = + std::vector>(g.size(), std::vector(height, -1)); + depth = std::vector(g.size(), -1); + dfs_mark_depth(g, root, root); +} + +int LCA::get_parent(int u, int v) { + if (depth[u] < depth[v]) { + int t = v; + v = u; + u = t; + } + int height = sparse_table[0].size(); + for (int i = height - 1; i >= 0; i--) { + if (depth[u] - (1 << i) >= depth[v]) { + u = sparse_table[u][i]; + } + } + if (u == v) { + return v; + } + for (int i = height - 1; i >= 0; i--) { + if (sparse_table[u][i] != sparse_table[v][i]) { + u = sparse_table[u][i]; + v = sparse_table[v][i]; + } + } + return sparse_table[u][0]; +} + +void LCA::dfs_mark_depth(const Graph& g, int v, int p) { + sparse_table[v][0] = p; + for (int i = 1; i < sparse_table[v].size(); i++) { + if (sparse_table[v][i - 1] != -1) { + sparse_table[v][i] = sparse_table[sparse_table[v][i - 1]][i - 1]; + } + } + for (const auto u : g.adjacents[v]) { + if (u.name != p) { + depth[u.name] = depth[v] + 1; + dfs_mark_depth(g, u.name, v); + } + } +} \ No newline at end of file diff --git a/task_06/src/lca.hpp b/task_06/src/lca.hpp new file mode 100644 index 0000000..3080801 --- /dev/null +++ b/task_06/src/lca.hpp @@ -0,0 +1,28 @@ +#ifndef LCA_H_ +#define LCA_H_ + +#include "../../lib/src/graph.h" + +std::vector* topological_sort_dfs_rec(Graph& g); + +double get_min_from_sparse_table(std::vector>& sparse_table, + std::vector& top_sort, int start_ind, + int end_ind); + +std::vector> lca_sparse_table(Graph& g, + std::vector& top_sort); + +class LCA { + public: + LCA(const Graph& g, int root); + + int get_parent(int u, int v); + + private: + std::vector> sparse_table; + std::vector depth; + + void dfs_mark_depth(const Graph& g, int v, int p); +}; + +#endif \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..7eb09bc 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,118 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "lca.hpp" + +bool dfs_find(Graph& g, std::vector& visited, int v, int to_find) { + visited[v] = true; + + for (auto child : g.adjacents[v]) { + if (visited[child.name]) { + continue; + } + if (child.name == to_find) { + return true; + } + if (dfs_find(g, visited, child.name, to_find)) { + return true; + } + } + return false; +} + +bool is_min_ancestor(Graph& g, int v, int u, int parent) { + if (parent == v && parent == u) { + return true; + } + bool v_found = (parent == v); + bool u_found = (parent == u); + int child_first_found = -1; + std::vector visited(g.size(), false); + + for (auto child : g.adjacents[parent]) { + if (!v_found && (child_first_found != child.name)) { + if (dfs_find(g, visited, parent, v)) { + child_first_found = child.name; + v_found = true; + } + } + } + visited = std::vector(g.size(), false); + + for (auto child : g.adjacents[parent]) { + if (!u_found && (child_first_found != child.name)) { + if (dfs_find(g, visited, parent, u)) { + child_first_found = child.name; + u_found = true; + } + } + } + return (u_found && v_found); +} + +TEST(native_ancestors_check, Test_1) { + Graph g(10, { + {2, 0}, + {2, 1}, + {4, 2}, + {8, 6}, + {4, 8}, + {4, 9}, + {4, 3}, + {3, 5}, + {3, 7}, + }); + LCA lca(g, 4); + + for (int i = 0; i < g.size(); ++i) { + for (int j = i; j < g.size(); ++j) { + ASSERT_EQ(is_min_ancestor(g, i, j, lca.get_parent(i, j)), true); + } + } +} + +TEST(native_ancestors_check, Test_2) { + Graph g(9, { + {1, 0}, + {1, 3}, + {3, 2}, + {3, 4}, + {5, 1}, + {5, 6}, + {6, 8}, + {8, 7}, + {3, 7}, + }); + LCA lca(g, 5); + + for (int i = 0; i < g.size(); ++i) { + for (int j = i; j < g.size(); ++j) { + ASSERT_EQ(is_min_ancestor(g, i, j, lca.get_parent(i, j)), true); + } + } +} + +TEST(native_ancestors_check, Test_3) { + Graph g(14, { + {1, 0}, + {1, 2}, + {2, 3}, + {3, 4}, + {5, 1}, + {5, 6}, + {6, 9}, + {9, 7}, + {7, 8}, + {9, 12}, + {12, 10}, + {10, 11}, + {12, 13}, + }); + LCA lca(g, 5); + + for (int i = 0; i < g.size(); ++i) { + for (int j = i; j < g.size(); ++j) { + ASSERT_EQ(is_min_ancestor(g, i, j, lca.get_parent(i, j)), true); + } + } }