diff --git a/task_01/src/graph.tpp b/task_01/src/graph.tpp new file mode 100644 index 0000000..ae66b9a --- /dev/null +++ b/task_01/src/graph.tpp @@ -0,0 +1,43 @@ +#ifndef AUTUMN_HOMEWORK_TASK_01_GRAPH_TPP_ +#define AUTUMN_HOMEWORK_TASK_01_GRAPH_TPP_ + +#include +#include + +template +class Graph { + private: + size_t v_num_; + std::vector> adj_; + + public: + Graph(size_t v_num) : v_num_{v_num}, adj_{v_num_} {} + + void AddEdge(size_t first_vertex, size_t second_vertex) { + adj_[first_vertex].push_back(second_vertex); + } + + void TopologicalSortVertex(int i, std::vector& visited, + std::list& list) { + for (auto neighbor : adj_[i]) { + if (!visited[neighbor]) { + TopologicalSortVertex(neighbor, visited, list); + } + } + list.push_front(i); + visited[i] = true; + } + + std::list TopologicalSort() { + std::list list; + std::vector visited(v_num_ + 1, false); + for (size_t i = 0; i < v_num_; i++) { + if (visited[i] == false) { + TopologicalSortVertex(i, visited, list); + } + } + return list; + } +}; + +#endif \ No newline at end of file diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 76e8197..5c92d29 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1 +1,6 @@ -int main() { return 0; } +#include + +int main() { + std::cout << "Lol" << std::endl; + return 0; +} \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..0b12119 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,56 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "graph.tpp" + +TEST(TopologicalSort, test1) { + Graph a(1); + + EXPECT_EQ(a.TopologicalSort(), std::list({0})); +} + +TEST(TopologicalSort, test2) { + Graph a(2); + + a.AddEdge(0, 1); + + EXPECT_EQ(a.TopologicalSort(), std::list({0, 1})); +} + +TEST(TopologicalSort, test3) { + Graph a(3); + + a.AddEdge(0, 1); + a.AddEdge(1, 2); + + EXPECT_EQ(a.TopologicalSort(), std::list({0, 1, 2})); +} + +TEST(TopologicalSort, test4) { + Graph a(6); + + a.AddEdge(0, 1); + a.AddEdge(0, 3); + a.AddEdge(1, 2); + a.AddEdge(3, 1); + a.AddEdge(3, 5); + a.AddEdge(3, 4); + a.AddEdge(4, 5); + + EXPECT_EQ(a.TopologicalSort(), std::list({0, 3, 4, 5, 1, 2})); +} + +TEST(TopologicalSort, test5) { + Graph a(7); + + a.AddEdge(0, 1); + a.AddEdge(0, 2); + a.AddEdge(1, 2); + a.AddEdge(1, 5); + a.AddEdge(2, 3); + a.AddEdge(5, 3); + a.AddEdge(5, 4); + a.AddEdge(6, 1); + a.AddEdge(6, 5); + + EXPECT_EQ(a.TopologicalSort(), std::list({6, 0, 1, 5, 4, 2, 3})); } \ No newline at end of file diff --git a/task_02/src/graph.tpp b/task_02/src/graph.tpp new file mode 100644 index 0000000..cf15c88 --- /dev/null +++ b/task_02/src/graph.tpp @@ -0,0 +1,69 @@ +#ifndef AUTUMN_HOMEWORK_TASK_02_GRAPH_TPP_ +#define AUTUMN_HOMEWORK_TASK_02_GRAPH_TPP_ + +#include +#include + +template +class Graph { + private: + size_t v_num_; + std::vector> adj_; + std::vector disc_, + least_; // discovery time and least_[i] is node with least disc_ that can + // be reached from i node + std::vector> br_; // bridges + std::vector a_p_; // articulation points + + void dfs(int u, int p, int& timer) { + disc_[u] = least_[u] = timer++; + int subgraph_count = 0; + + for (int v : adj_[u]) { + if (v == p) continue; + if (disc_[v]) { + least_[u] = std::min(least_[u], disc_[v]); + } else { + ++subgraph_count; + dfs(v, u, timer); + least_[u] = std::min(least_[u], least_[v]); + + if (disc_[u] <= least_[v] && p != -1) { + if (a_p_.empty() || a_p_.back() != u) { + a_p_.push_back(u); + } + } + if (disc_[u] < least_[v]) br_.push_back({u, v}); + } + } + + if (subgraph_count > 1 && p == -1) a_p_.push_back(u); + } + + public: + Graph(size_t number) { + v_num_ = number; + adj_ = std::vector>(v_num_); + } + + void AddEdge(size_t first_verticle, size_t second_verticle) { + adj_[first_verticle].push_back(second_verticle); + adj_[second_verticle].push_back(first_verticle); + } + + void UpdateBrAp() { + int timer = 1; + disc_.assign(v_num_, 0); + least_.assign(v_num_, 0); + br_.clear(); + a_p_.clear(); + + for (size_t i = 0; i < v_num_; ++i) { + if (!disc_[i]) dfs(i, -1, timer); + } + } + + std::vector> GetBr() { return br_; } + std::vector GetAP() { return a_p_; } +}; +#endif \ No newline at end of file diff --git a/task_02/src/main.cpp b/task_02/src/main.cpp index 0e4393b..b81cc05 100644 --- a/task_02/src/main.cpp +++ b/task_02/src/main.cpp @@ -1,3 +1,6 @@ #include -int main() { return 0; } +int main() { + std::cout << "Lol" << std::endl; + return 0; +} 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..70f8645 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,42 +1,153 @@ #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 "graph.tpp" + +TEST(BridgeGraphTest, test1) { + Graph a(5); + + a.AddEdge(0, 1); + a.AddEdge(1, 2); + a.AddEdge(2, 3); + a.AddEdge(2, 4); + a.AddEdge(3, 4); + + a.UpdateBrAp(); + + std::vector> bridges({{1, 2}, {0, 1}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({2, 1}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test2) { + Graph a(5); + + a.AddEdge(0, 1); + a.AddEdge(1, 2); + a.AddEdge(1, 3); + a.AddEdge(2, 3); + a.AddEdge(2, 4); + + a.UpdateBrAp(); + + std::vector> bridges({{2, 4}, {0, 1}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({2, 1}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test3) { + Graph a(8); + + a.AddEdge(0, 1); + a.AddEdge(0, 2); + a.AddEdge(0, 3); + a.AddEdge(3, 4); + a.AddEdge(3, 5); + a.AddEdge(4, 6); + a.AddEdge(5, 6); + a.AddEdge(5, 7); + a.AddEdge(6, 7); + + a.UpdateBrAp(); + + std::vector> bridges({{0, 1}, {0, 2}, {0, 3}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({3, 0}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test4) { + Graph a(3); + + a.AddEdge(0, 1); + a.AddEdge(0, 2); + a.AddEdge(2, 1); + + a.UpdateBrAp(); + + std::vector> bridges({}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test5) { + Graph a(3); + + a.UpdateBrAp(); + + std::vector> bridges({}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test6) { + Graph a(7); + + a.AddEdge(0, 1); + a.AddEdge(0, 2); + a.AddEdge(2, 1); + a.AddEdge(3, 4); + a.AddEdge(3, 5); + a.AddEdge(3, 6); + a.AddEdge(4, 5); + + a.UpdateBrAp(); + + std::vector> bridges({{3, 6}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({3}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test7) { + Graph a(7); + + a.AddEdge(0, 1); + a.AddEdge(0, 2); + a.AddEdge(3, 4); + a.AddEdge(3, 5); + a.AddEdge(3, 6); + a.AddEdge(4, 5); + + a.UpdateBrAp(); + + std::vector> bridges({{0, 1}, {0, 2}, {3, 6}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({0, 3}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test8) { + Graph a(5); + + a.AddEdge(0, 1); + a.AddEdge(1, 2); + a.AddEdge(1, 3); + a.AddEdge(2, 3); + a.AddEdge(2, 4); + a.AddEdge(3, 4); + + a.UpdateBrAp(); + + std::vector> bridges({{0, 1}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({1}); + EXPECT_EQ(a.GetAP(), articulation_points); +} + +TEST(BridgeGraphTest, test9) { + Graph a(2); + + a.AddEdge(0, 1); + + a.UpdateBrAp(); + + std::vector> bridges({{0, 1}}); + EXPECT_EQ(a.GetBr(), bridges); + std::vector articulation_points({}); + EXPECT_EQ(a.GetAP(), articulation_points); } \ No newline at end of file diff --git a/task_03/src/graph.cpp b/task_03/src/graph.cpp new file mode 100644 index 0000000..cbff1be --- /dev/null +++ b/task_03/src/graph.cpp @@ -0,0 +1,66 @@ +#include "graph.hpp" + +Graph::Graph(const std::vector>& adj_matr) + : adj_matr_(adj_matr), v_num_(adj_matr.size()) {} + +bool Graph::BellmanFord(std::vector& h) { + std::vector distances(v_num_, kInf); + distances[v_num_ - 1] = 0; + for (size_t i = 0; i < v_num_ - 1; ++i) RelaxEdges(distances); + h = distances; + return HasNegativeCycle(distances); +} + +bool Graph::HasNegativeCycle(const std::vector& distances) { + for (size_t u = 0; u < v_num_; ++u) + for (size_t v = 0; v < v_num_; ++v) + if (adj_matr_[u][v] != kInf && distances[u] != kInf) + if (distances[u] + adj_matr_[u][v] < distances[v]) return true; + return false; +} + +void Graph::RelaxEdges(std::vector& distances) { + for (size_t u = 0; u < v_num_; ++u) + for (size_t v = 0; v < v_num_; ++v) + if (adj_matr_[u][v] != kInf && distances[u] != kInf) + if (distances[u] + adj_matr_[u][v] < distances[v]) + distances[v] = distances[u] + adj_matr_[u][v]; +} + +std::vector> Graph::Johnson() { + std::vector h(v_num_, 0); + if (BellmanFord(h)) exit(1); + for (size_t u = 0; u < v_num_; ++u) + for (size_t v = 0; v < v_num_; ++v) + if (adj_matr_[u][v] != kInf) adj_matr_[u][v] += h[u] - h[v]; + std::vector> dist(v_num_); + for (size_t u = 0; u < v_num_; ++u) { + dist[u] = Dijkstra(u); + for (size_t v = 0; v < v_num_; ++v) + if (dist[u][v] != kInf) dist[u][v] += h[v] - h[u]; + } + return dist; +} + +std::vector Graph::Dijkstra(size_t s) { + std::vector dist_s(v_num_, kInf); + dist_s[s] = 0; + std::priority_queue, std::vector>, + std::greater>> + q; + q.push({0, s}); + while (!q.empty()) { + auto [cur_dist, v] = q.top(); + q.pop(); + if (cur_dist > dist_s[v]) continue; + for (size_t u = 0; u < v_num_; ++u) { + const int w = adj_matr_[v][u]; + if (w != kInf && dist_s[v] != kInf) + if (dist_s[v] + w < dist_s[u]) { + dist_s[u] = dist_s[v] + w; + q.push({dist_s[v] + w, u}); + } + } + } + return dist_s; +} diff --git a/task_03/src/graph.hpp b/task_03/src/graph.hpp new file mode 100644 index 0000000..a9d0ba6 --- /dev/null +++ b/task_03/src/graph.hpp @@ -0,0 +1,30 @@ +#ifndef AUTUMN_HOMEWORK_TASK_03_GRAPH_HPP_ +#define AUTUMN_HOMEWORK_TASK_03_GRAPH_HPP_ + +#include +#include +#include +#include + +const int kInf = std::numeric_limits::max(); + +class Graph { + public: + Graph(const std::vector>& adj_matr); + + std::vector Dijkstra(size_t s); + + std::vector> Johnson(); + + private: + std::vector> adj_matr_; + size_t v_num_; + + bool HasNegativeCycle(const std::vector& distances); + + void RelaxEdges(std::vector& distances); + + bool BellmanFord(std::vector& h); +}; + +#endif \ No newline at end of file diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp index 0e4393b..b81cc05 100644 --- a/task_03/src/main.cpp +++ b/task_03/src/main.cpp @@ -1,3 +1,6 @@ #include -int main() { return 0; } +int main() { + std::cout << "Lol" << std::endl; + return 0; +} diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..16766db 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,111 @@ - #include -#include "topology_sort.hpp" +#include "graph.hpp" + +using namespace std; + +TEST(Johnson, test1) { + vector> adj_matr = {{0, 10, kInf, 30, 100}, + {kInf, 0, 50, kInf, kInf}, + {kInf, kInf, 0, kInf, 10}, + {kInf, kInf, 20, 0, 60}, + {kInf, kInf, kInf, kInf, 0}}; + vector> result = {{0, 10, 50, 30, 60}, + {kInf, 0, 50, kInf, 60}, + {kInf, kInf, 0, kInf, 10}, + {kInf, kInf, 20, 0, 30}, + {kInf, kInf, kInf, kInf, 0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test2) { + vector> adj_matr = {{0}}; + vector> result = {{0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test3) { + vector> adj_matr = { + {0, kInf, kInf}, {kInf, 0, kInf}, {kInf, kInf, 0}}; + vector> result = { + {0, kInf, kInf}, {kInf, 0, kInf}, {kInf, kInf, 0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test4) { + vector> adj_matr = {{0, 1, 3}, {1, 0, -1}, {3, kInf, 0}}; + vector> result = {{0, 1, 0}, {1, 0, -1}, {3, 4, 0}}; + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test5) { + vector> adj_matr = {{0, 1, 1}, {1, 0, -1}, {1, kInf, 0}}; + vector> result = {{0, 1, 0}, {0, 0, -1}, {1, 2, 0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test6) { + vector> adj_matr = {{0, 1, 1}, {1, 0, -2}, {1, kInf, 0}}; + vector> result = {{0, 1, -1}, {-1, 0, -2}, {1, 2, 0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test7) { + vector> adj_matr = { + {0, 1, 1, kInf, kInf, kInf, kInf}, {1, 0, 1, kInf, kInf, kInf, kInf}, + {1, 1, 0, kInf, kInf, kInf, kInf}, {kInf, kInf, kInf, 0, 1, 1, 1}, + {kInf, kInf, kInf, 1, 0, 1, kInf}, {kInf, kInf, kInf, 1, 1, 0, kInf}, + {kInf, kInf, kInf, 1, kInf, kInf, 0}}; + vector> result = { + {0, 1, 1, kInf, kInf, kInf, kInf}, {1, 0, 1, kInf, kInf, kInf, kInf}, + {1, 1, 0, kInf, kInf, kInf, kInf}, {kInf, kInf, kInf, 0, 1, 1, 1}, + {kInf, kInf, kInf, 1, 0, 1, 2}, {kInf, kInf, kInf, 1, 1, 0, 2}, + {kInf, kInf, kInf, 1, 2, 2, 0}}; + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test8) { + vector> adj_matr = {{0, 1, 3, kInf}, + {1, 0, -1, kInf}, + {3, kInf, 0, kInf}, + {kInf, kInf, kInf, 0}}; + vector> result = {{0, 1, 0, kInf}, + {1, 0, -1, kInf}, + {3, 4, 0, kInf}, + {kInf, kInf, kInf, 0}}; + + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); +} + +TEST(Johnson, test9) { + vector> adj_matr = {{0, 1, 2, kInf, kInf, kInf, kInf}, + {kInf, 0, kInf, 1, kInf, kInf, kInf}, + {kInf, kInf, 0, kInf, 1, 4, kInf}, + {kInf, kInf, kInf, 0, kInf, kInf, kInf}, + {kInf, kInf, kInf, kInf, 0, kInf, 3}, + {kInf, kInf, kInf, kInf, kInf, 0, kInf}, + {kInf, kInf, kInf, kInf, kInf, kInf, 0}}; + vector> result = {{0, 1, 2, 2, 3, 6, 6}, + {kInf, 0, kInf, 1, kInf, kInf, kInf}, + {kInf, kInf, 0, kInf, 1, 4, 4}, + {kInf, kInf, kInf, 0, kInf, kInf, kInf}, + {kInf, kInf, kInf, kInf, 0, kInf, 3}, + {kInf, kInf, kInf, kInf, kInf, 0, kInf}, + {kInf, kInf, kInf, kInf, kInf, kInf, 0}}; -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] + Graph a(adj_matr); + EXPECT_EQ(a.Johnson(), result); } 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/graph.cpp b/task_04/src/graph.cpp new file mode 100644 index 0000000..1610140 --- /dev/null +++ b/task_04/src/graph.cpp @@ -0,0 +1,27 @@ +#include "graph.hpp" + +Graph::Graph(const std::vector>& adj_matr) + : adj_matr_(adj_matr), v_num_(adj_matr.size()) {} + +std::vector Graph::Dijkstra(size_t s) { + std::vector dist_s(v_num_, kInf); + dist_s[s] = 0; + std::priority_queue, std::vector>, + std::greater>> + q; + q.push({0, s}); + while (!q.empty()) { + auto [cur_dist, v] = q.top(); + q.pop(); + if (cur_dist > dist_s[v]) continue; + for (size_t u = 0; u < v_num_; ++u) { + const int w = adj_matr_[v][u]; + if (w != kInf && dist_s[v] != kInf) + if (dist_s[v] + w < dist_s[u]) { + dist_s[u] = dist_s[v] + w; + q.push({dist_s[v] + w, u}); + } + } + } + return dist_s; +} diff --git a/task_04/src/graph.hpp b/task_04/src/graph.hpp new file mode 100644 index 0000000..afe62f7 --- /dev/null +++ b/task_04/src/graph.hpp @@ -0,0 +1,22 @@ +#ifndef AUTUMN_HOMEWORK_TASK_04_GRAPH_HPP_ +#define AUTUMN_HOMEWORK_TASK_04_GRAPH_HPP_ + +#include +#include +#include +#include + +const int kInf = std::numeric_limits::max(); + +class Graph { + private: + std::vector> adj_matr_; + size_t v_num_; + + public: + Graph(const std::vector>& adj_matr); + + std::vector Dijkstra(size_t s); +}; + +#endif \ No newline at end of file diff --git a/task_04/src/main.cpp b/task_04/src/main.cpp index 0e4393b..b81cc05 100644 --- a/task_04/src/main.cpp +++ b/task_04/src/main.cpp @@ -1,3 +1,6 @@ #include -int main() { return 0; } +int main() { + std::cout << "Lol" << std::endl; + return 0; +} diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..8e4669c 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,90 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "graph.hpp" + +using namespace std; + +TEST(Dijkstra, test1) { + vector> adj_matr = {{0, 10, kInf, 30, 100}, + {kInf, 0, 50, kInf, kInf}, + {kInf, kInf, 0, kInf, 10}, + {kInf, kInf, 20, 0, 60}, + {kInf, kInf, kInf, kInf, 0}}; + vector result = {0, 10, 50, 30, 60}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); +} + +TEST(Dijkstra, test2) { + vector> adj_matr = {{0}}; + vector result = {0}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); +} + +TEST(Dijkstra, test3) { + vector> adj_matr = { + {0, kInf, kInf}, {kInf, 0, kInf}, {kInf, kInf, 0}}; + vector result = {0, kInf, kInf}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); +} + +TEST(Dijkstra, test4) { + vector> adj_matr = {{0, 1, 3}, {1, 0, -1}, {3, kInf, 0}}; + vector result = {0, 1, 0}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); +} + +TEST(Dijkstra, test5) { + vector> adj_matr = { + {0, 1, 1, kInf, kInf, kInf, kInf}, {1, 0, 1, kInf, kInf, kInf, kInf}, + {1, 1, 0, kInf, kInf, kInf, kInf}, {kInf, kInf, kInf, 0, 1, 1, 1}, + {kInf, kInf, kInf, 1, 0, 1, kInf}, {kInf, kInf, kInf, 1, 1, 0, kInf}, + {kInf, kInf, kInf, 1, kInf, kInf, 0}}; + vector result = {0, 1, 1, kInf, kInf, kInf, kInf}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); +} +TEST(Dijkstra, test6) { + vector> adj_matr = { + {0, 1, 1, kInf, kInf, kInf, kInf}, {1, 0, 1, kInf, kInf, kInf, kInf}, + {1, 1, 0, kInf, kInf, kInf, kInf}, {kInf, kInf, kInf, 0, 1, 1, 1}, + {kInf, kInf, kInf, 1, 0, 1, kInf}, {kInf, kInf, kInf, 1, 1, 0, kInf}, + {kInf, kInf, kInf, 1, kInf, kInf, 0}}; + vector result = {kInf, kInf, kInf, 1, 0, 1, 2}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(4), result); +} + +TEST(Dijkstra, test7) { + vector> adj_matr = {{0, 1, 3, kInf}, + {1, 0, -1, kInf}, + {3, kInf, 0, kInf}, + {kInf, kInf, kInf, 0}}; + vector result = {kInf, kInf, kInf, 0}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(3), result); +} + +TEST(Dijkstra, test8) { + vector> adj_matr = {{0, 1, 2, kInf, kInf, kInf, kInf}, + {kInf, 0, kInf, 1, kInf, kInf, kInf}, + {kInf, kInf, 0, kInf, 1, 4, kInf}, + {kInf, kInf, kInf, 0, kInf, kInf, kInf}, + {kInf, kInf, kInf, kInf, 0, kInf, 3}, + {kInf, kInf, kInf, kInf, kInf, 0, kInf}, + {kInf, kInf, kInf, kInf, kInf, kInf, 0}}; + vector result = {0, 1, 2, 2, 3, 6, 6}; + + Graph a(adj_matr); + EXPECT_EQ(a.Dijkstra(0), result); } diff --git a/task_05/COMMENTS.md b/task_05/COMMENTS.md new file mode 100644 index 0000000..df36ce8 --- /dev/null +++ b/task_05/COMMENTS.md @@ -0,0 +1,12 @@ +У меня две задачи (lca и rmq) оказались очень связанными и интересными. Для того, чтобы реализовать lca я использовал rmq+-1 (что более узкий случай по сравнению с rmq). Для того, чтобы решить задачу rmq+-1 использовал алгоритм Фарака-Колтона и Бендера. Сложность для rmq+-1 составила O(n) на построение (по сравнению с O(nlogn) для общего rmq на разряженных таблицах) и O(1) на нахождения минимума. + +Таким образом получаю решение lca с построением O(n) и нахождением общего предка за O(1). +Потом я использовал алгоритм lca ( O(n), O(1) ) для решения rmq. Только предварительно надо было построить декартово дерево по неявному ключу. +Это дерево: +* Корнем дерева является элемент массива, имеющий минимальное значение A, скажем A[i]. Если минимальных элементов несколько, можно взять любой. +* Левым поддеревом является декартово дерево на массиве A[1..i−1]. +* Правым поддеревом является декартово дерево на массиве A[i+1..N]. + +Его построение реализовал за O(n) - кроме построения ничего и не требуется. Таким образом получил rmq (O(n), O(1)) :) + +Внимание. Я не делал доп проверок на то, что в lca подано именно дерево, и др проверк на дурака. Ситаю, что подается дерево с >=1 вершиной. В rmq массив должен быть длины >= 1 diff --git a/task_05/src/dectree.tpp b/task_05/src/dectree.tpp new file mode 100644 index 0000000..b19fe63 --- /dev/null +++ b/task_05/src/dectree.tpp @@ -0,0 +1,62 @@ +#ifndef AUTUMN_HOMEWORK_TASK_05_DECTREE_TPP_ +#define AUTUMN_HOMEWORK_TASK_05_DECTREE_TPP_ + +#include +#include + +using namespace std; + +// для реализации rmq через lca надо использовать +// декартово дерево по неявному ключу +// требуется только построение дерева + +template +class DecTree { + size_t n_; + vector values_; + vector> adj_l_; + vector parents; + + public: + DecTree(vector arr) : n_{arr.size()}, values_{arr}, adj_l_(n_) { + parents = vector(n_, -1); + for (size_t i = 1; i < n_; ++i) { + if (values_[i - 1] > arr[i]) { + // поднимаем наверх + size_t ptr_r = -1; + size_t ptr = i - 1; + for (; parents[ptr] != -1 && values_[ptr] > arr[i]; + ptr_r = ptr, ptr = parents[ptr]); + if (values_[ptr] <= arr[i]) { + adj_l_[ptr].erase(ptr_r); + adj_l_[ptr].insert(i); + adj_l_[i].insert(ptr_r); + parents[ptr_r] = i; + parents[i] = ptr; + } else { + parents[ptr] = i; + adj_l_[i].insert(ptr); + } + } else { + // пробуем записать в сыны + adj_l_[i - 1].insert(i); + parents[i] = i - 1; + } + } + } + vector> GetAdj() { + vector> adj = vector>(n_, vector()); + for (size_t i = 0; i < n_; ++i) + adj[i] = vector(adj_l_[i].begin(), adj_l_[i].end()); + return adj; + } + + size_t GetStart() { + for (size_t i = 0; i < n_; ++i) + if (parents[i] == -1) return i; + return -1; + } + vector GetValues() { return values_; } +}; + +#endif \ No newline at end of file diff --git a/task_05/src/lca_tree.tpp b/task_05/src/lca_tree.tpp new file mode 100644 index 0000000..fd469dc --- /dev/null +++ b/task_05/src/lca_tree.tpp @@ -0,0 +1,51 @@ +#ifndef AUTUMN_HOMEWORK_TASK_05_LCA_TREE_TPP_ +#define AUTUMN_HOMEWORK_TASK_05_LCA_TREE_TPP_ +#include +#include +#include +// то же самое, что в задаче 06 + +#include "rmq_1_array.tpp" + +using namespace std; + +template +class LcaTree { + public: + size_t lca(size_t u, size_t v) { return vtx_[rmq_.rmq1(I_[u], I_[v]).i]; } + T lca_value(size_t u, size_t v) { return values_[lca(u, v)]; } + LcaTree(vector> adj_l, size_t start) + : adj_l_{adj_l}, v_num_{adj_l.size()}, I_(v_num_, -1) { + dfs(start, 0); + rmq_ = Rmq_1_Array{d_}; + values_ = vector(v_num_); + } + LcaTree(vector> adj_l, size_t start, vector values) + : adj_l_{adj_l}, v_num_{adj_l.size()}, I_(v_num_, -1), values_{values} { + dfs(start, 0); + rmq_ = Rmq_1_Array{d_}; + } + LcaTree() {} + void setValues(vector values) { values_ = vector(v_num_); } + + private: + Rmq_1_Array rmq_; + vector> adj_l_; + size_t v_num_; + vector d_; + vector vtx_; + vector I_; + vector values_; + void dfs(size_t v, size_t cur_d) { + d_.push_back(cur_d); + vtx_.push_back(v); + if (I_[v] == -1) I_[v] = d_.size() - 1; + for (auto& u : adj_l_[v]) { + dfs(u, cur_d + 1); + d_.push_back(cur_d); + vtx_.push_back(v); + } + } +}; + +#endif \ No newline at end of file diff --git a/task_05/src/main.cpp b/task_05/src/main.cpp index 0e4393b..396bf03 100644 --- a/task_05/src/main.cpp +++ b/task_05/src/main.cpp @@ -1,3 +1,18 @@ #include -int main() { return 0; } +#include "dectree.tpp" +#include "rmq_array.tpp" + +int main() { + vector v{17, 0, 36, 16, 23, 15, 42, 18, 20}; + DecTree d(v); + auto data = d.GetAdj(); + for (auto i : data) { + for (auto j : i) std::cout << j << " "; + std::cout << std::endl; + } + RmqArray rmq(v); + std::cout << "------------------" << std::endl; + std::cout << rmq.rmq(4, 6) << std::endl; + return 0; +} \ No newline at end of file diff --git a/task_05/src/rmq_1_array.tpp b/task_05/src/rmq_1_array.tpp new file mode 100644 index 0000000..c088d8c --- /dev/null +++ b/task_05/src/rmq_1_array.tpp @@ -0,0 +1,124 @@ +#ifndef AUTUMN_HOMEWORK_TASK_05_RMQ_1_ARRAY_TPP_ +#define AUTUMN_HOMEWORK_TASK_05_RMQ_1_ARRAY_TPP_ +#include +#include + +// то же самое, что в задаче 06 + +using namespace std; +template +class Rmq_1_Array { + public: + struct MinIndexPair { + size_t i; + T min; + MinIndexPair() = default; + MinIndexPair(std::size_t i, const vector& arr) { + this->i = i; + min = arr[i]; + } + }; + Rmq_1_Array(vector arr) : arr_{arr}, n_{arr.size()} { precalc(); } + Rmq_1_Array(){}; + Rmq_1_Array& operator=(const Rmq_1_Array& other) { + n_ = other.n_; + arr_ = other.arr_; + block_min_ = other.block_min_; + b_ = other.b_; + sparce_table_b_ = other.sparce_table_b_; + type_ = other.type_; + block_size_ = other.block_size_; + return *this; + } + MinIndexPair rmq1(size_t l, size_t r) { + if (l > r) swap(l, r); + size_t bl = l / block_size_; + size_t br = r / block_size_; + auto temp = blockRmq(bl, l % block_size_, r % block_size_); + if (bl == br) + return MinIndexPair(blockRmq(bl, l % block_size_, r % block_size_), arr_); + + MinIndexPair ans_l(blockRmq(bl, l % block_size_, block_size_ - 1), arr_); + MinIndexPair ans_r(blockRmq(br, 0, r % block_size_), arr_); + MinIndexPair min_lr = ans_l.min < ans_r.min ? ans_l : ans_r; + if (bl + 1 < br) { + size_t power = log(br - bl - 1); + + MinIndexPair ans_b; + if (arr_[sparce_table_b_[bl + 1llu][power]] < + arr_[sparce_table_b_[br - (1llu << power)][power]]) + ans_b = MinIndexPair(sparce_table_b_[bl + 1llu][power], arr_); + else + ans_b = + MinIndexPair(sparce_table_b_[br - (1llu << power)][power], arr_); + + return ans_b.min < min_lr.min ? ans_b : min_lr; + } + return min_lr; + } + + private: + size_t n_; + vector arr_; + vector>> block_min_; + vector b_; + vector> sparce_table_b_; + vector type_; + size_t block_size_; + void precalc() { + block_size_ = log(n_); + if (block_size_ == 0) exit(-1); + size_t k = n_ % block_size_ == 0 ? n_ / block_size_ : n_ / block_size_ + 1; + T cur_block = -1; + b_ = vector(k, -1); + for (size_t i = 0; i < n_; ++i) { + if (i % block_size_ == 0) cur_block++; + if (b_[cur_block] == -1 || arr_[b_[cur_block]] > arr_[i]) + b_[cur_block] = i; + } + sparce_table_b_ = vector>(k, vector(log(n_) + 1)); + for (size_t i = 0; i < k; ++i) sparce_table_b_[i][0] = b_[i]; + for (size_t j = 1; j <= log(n_); ++j) + for (size_t i = 0; i < k; ++i) { + size_t ind = (1 << (j - 1)) + i; + if (ind >= k) + sparce_table_b_[i][j] = sparce_table_b_[i][j - 1]; + else if (arr_[sparce_table_b_[i][j - 1]] > + arr_[sparce_table_b_[ind][j - 1]]) + sparce_table_b_[i][j] = sparce_table_b_[ind][j - 1]; + else + sparce_table_b_[i][j] = sparce_table_b_[i][j - 1]; + } + type_ = vector(k, 0); + cur_block = 0; + for (size_t j = 0, i = 0; i < n_ or j < block_size_; ++j, ++i) { + if (j >= block_size_) { + j = 0; + cur_block++; + } + if (j > 0 and (i >= n_ or arr_[i - 1] < arr_[i])) + type_[cur_block] += (1 << (j - 1)); + } + block_min_ = vector>>( + k, vector>(block_size_, vector(block_size_, -1))); + for (size_t i = 0; i < k; ++i) { + size_t t = type_[i]; + if (block_min_[t][0][0] == -1) + for (size_t l = 0; l < block_size_; ++l) { + block_min_[t][l][l] = l; + for (size_t r = l + 1; r < block_size_; ++r) { + block_min_[t][l][r] = block_min_[t][l][r - 1]; + if (i * block_size_ + r <= n_ and + arr_[i * block_size_ + block_min_[t][l][r]] > + arr_[i * block_size_ + r]) + block_min_[t][l][r] = r; + } + } + } + } + T blockRmq(size_t block_num, size_t l, size_t r) { + return block_min_[type_[block_num]][l][r] + block_num * block_size_; + } +}; + +#endif \ No newline at end of file diff --git a/task_05/src/rmq_array.tpp b/task_05/src/rmq_array.tpp new file mode 100644 index 0000000..f2fdda9 --- /dev/null +++ b/task_05/src/rmq_array.tpp @@ -0,0 +1,28 @@ +#ifndef AUTUMN_HOMEWORK_TASK_05_RMQ_ARRAY_TPP_ +#define AUTUMN_HOMEWORK_TASK_05_RMQ_ARRAY_TPP_ + +#include + +#include "dectree.tpp" +#include "lca_tree.tpp" +using namespace std; + +template +struct RmqArray { + vector arr_; + size_t n_; + LcaTree lca_tree_; + RmqArray(vector arr) : arr_{arr}, n_{arr.size()} { + if (n_ > 1) { + DecTree dec_tree(arr_); + lca_tree_ = LcaTree(dec_tree.GetAdj(), dec_tree.GetStart(), arr_); + } + } + + T rmq(size_t l, size_t r) { + if (n_ > 1) return lca_tree_.lca_value(l, r); + return arr_[0]; + } +}; + +#endif \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..a05c0fd 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,56 @@ + #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "rmq_array.tpp" + +using namespace std; + +// алгоритм не делает проверку на дурака! должны подаваться только валидные +// деревья + +TEST(Rmq, test1) { + vector v{10, 3, 2, 17, 2, 1}; + RmqArray r(v); + EXPECT_EQ(r.rmq(0, 0), 10); + EXPECT_EQ(r.rmq(0, 1), 3); + EXPECT_EQ(r.rmq(0, 2), 2); + EXPECT_EQ(r.rmq(0, 3), 2); + EXPECT_EQ(r.rmq(0, 4), 2); + EXPECT_EQ(r.rmq(0, 5), 1); +} + +TEST(Rmq, test2) { + vector v{10, 3, 2, 17, 2, 1}; + RmqArray r(v); + EXPECT_EQ(r.rmq(0, 1), 3); + EXPECT_EQ(r.rmq(2, 1), 2); + EXPECT_EQ(r.rmq(3, 2), 2); + EXPECT_EQ(r.rmq(4, 3), 2); + EXPECT_EQ(r.rmq(5, 4), 1); +} + +TEST(Rmq, test3) { + vector v{10, 3, 2, 17, 2, 1}; + RmqArray r(v); + EXPECT_EQ(r.rmq(3, 5), 1); + EXPECT_EQ(r.rmq(4, 1), 2); + EXPECT_EQ(r.rmq(0, 3), 2); + EXPECT_EQ(r.rmq(2, 4), 2); + EXPECT_EQ(r.rmq(5, 1), 1); } + +TEST(Rmq, test4) { + vector v{100, 0}; + RmqArray r(v); + EXPECT_EQ(r.rmq(0, 0), 100); + EXPECT_EQ(r.rmq(1, 1), 0); +} + +TEST(Rmq, test5) { + vector v{100}; + RmqArray r(v); + EXPECT_EQ(r.rmq(0, 0), 100); +} \ No newline at end of file diff --git a/task_06/src/lca_tree.tpp b/task_06/src/lca_tree.tpp new file mode 100644 index 0000000..c76c64c --- /dev/null +++ b/task_06/src/lca_tree.tpp @@ -0,0 +1,56 @@ +#ifndef AUTUMN_HOMEWORK_TASK_06_LCA_TREE_TPP_ +#define AUTUMN_HOMEWORK_TASK_06_LCA_TREE_TPP_ +#include +#include +#include + +#include "rmq_1_array.tpp" + +using namespace std; + +template +class LcaTree { + public: + size_t lca(size_t u, size_t v) { + if (v_num_ > 1) return vtx_[rmq_.rmq1(I_[u], I_[v]).i]; + return 0; + } + T lca_value(size_t u, size_t v) { return values_[lca(u, v)]; } + LcaTree(vector> adj_l, size_t start) + : adj_l_{adj_l}, v_num_{adj_l.size()}, I_(v_num_, -1) { + if (v_num_ > 1) { + dfs(start, 0); + rmq_ = Rmq_1_Array{d_}; + } + values_ = vector(v_num_); + } + LcaTree(vector> adj_l, size_t start, vector values) + : adj_l_{adj_l}, v_num_{adj_l.size()}, I_(v_num_, -1), values_{values} { + if (v_num_ > 1) { + dfs(start, 0); + rmq_ = Rmq_1_Array{d_}; + } + } + void setValues(vector values) { values_ = vector(v_num_); } + + private: + Rmq_1_Array rmq_; + vector> adj_l_; + size_t v_num_; + vector d_; + vector vtx_; + vector I_; + vector values_; + void dfs(size_t v, size_t cur_d) { + d_.push_back(cur_d); + vtx_.push_back(v); + if (I_[v] == -1) I_[v] = d_.size() - 1; + for (auto& u : adj_l_[v]) { + dfs(u, cur_d + 1); + d_.push_back(cur_d); + vtx_.push_back(v); + } + } +}; + +#endif \ No newline at end of file diff --git a/task_06/src/main.cpp b/task_06/src/main.cpp index 0e4393b..ddc4f28 100644 --- a/task_06/src/main.cpp +++ b/task_06/src/main.cpp @@ -1,3 +1,11 @@ #include -int main() { return 0; } +#include "lca_tree.tpp" + +int main() { + vector> list = {{1, 2}, {3, 4}, {5, 6}, {}, {7, 8}, + {}, {}, {}, {}}; + LcaTree t(list, 0); + cout << t.lca(6, 2) << std::endl; + return 0; +} \ No newline at end of file diff --git a/task_06/src/rmq_1_array.tpp b/task_06/src/rmq_1_array.tpp new file mode 100644 index 0000000..e7b4da6 --- /dev/null +++ b/task_06/src/rmq_1_array.tpp @@ -0,0 +1,135 @@ +#ifndef AUTUMN_HOMEWORK_TASK_06_RMQ_1_ARRAY_TPP_ +#define AUTUMN_HOMEWORK_TASK_06_RMQ_1_ARRAY_TPP_ +#include +#include +#include + +using namespace std; +// rmq+-1 -- rmq для массива, в котором все соседи отличаются на +-1 +// сложность получения O(1) и сложность построения O(n) +template +class Rmq_1_Array { + public: + struct MinIndexPair { + size_t i; + T min; + MinIndexPair() = default; + MinIndexPair(std::size_t i, const vector& arr) { + this->i = i; + min = arr[i]; + } + }; + Rmq_1_Array(vector arr) : arr_{arr}, n_{arr.size()} { precalc(); } + Rmq_1_Array(){}; + Rmq_1_Array& operator=(const Rmq_1_Array& other) { + n_ = other.n_; + arr_ = other.arr_; + block_min_ = other.block_min_; + b_ = other.b_; + sparce_table_b_ = other.sparce_table_b_; + type_ = other.type_; + block_size_ = other.block_size_; + return *this; + } + MinIndexPair rmq1(size_t l, size_t r) { + if (l > r) swap(l, r); + size_t bl = l / block_size_; + size_t br = r / block_size_; + if (bl == br) // < если оба индекса внутри одного блока + + return MinIndexPair(blockRmq(bl, l % block_size_, r % block_size_), arr_); + + MinIndexPair ans_l(blockRmq(bl, l % block_size_, block_size_ - 1), arr_); + // ^^^ найдем минимум на отрезке от l до конца блока, содержащего l + MinIndexPair ans_r(blockRmq(br, 0, r % block_size_), arr_); + // ^^^ найдем минимум от начала блока, содержащего r, до r + MinIndexPair min_lr = ans_l.min < ans_r.min ? ans_l : ans_r; + // vvv найдем минимум на блоках между крайними, если таковые есть + if (bl + 1 < br) { + size_t power = log(br - bl - 1); + + MinIndexPair ans_b; + if (arr_[sparce_table_b_[bl + 1llu][power]] < + arr_[sparce_table_b_[br - (1llu << power)][power]]) + ans_b = MinIndexPair(sparce_table_b_[bl + 1llu][power], arr_); + else + ans_b = + MinIndexPair(sparce_table_b_[br - (1llu << power)][power], arr_); + + return ans_b.min < min_lr.min ? ans_b : min_lr; + } + return min_lr; + } + + private: + size_t n_; + vector arr_; + vector>> block_min_; + vector b_; + vector> sparce_table_b_; + vector type_; + size_t block_size_; + void precalc() { + block_size_ = log(n_); // размеры блоков + if (block_size_ == 0) exit(-1); + size_t k = n_ % block_size_ == 0 ? n_ / block_size_ : n_ / block_size_ + 1; + // ^^^ количество блоков + // vvv подсчет позиций минимумов в каждом блоке + T cur_block = -1; + b_ = vector(k, -1); + for (size_t i = 0; i < n_; ++i) { + if (i % block_size_ == 0) cur_block++; + if (b_[cur_block] == -1 || arr_[b_[cur_block]] > arr_[i]) + b_[cur_block] = i; + } + // vvv построение разреженной таблицы на b_ + sparce_table_b_ = vector>(k, vector(log(n_) + 1)); + for (size_t i = 0; i < k; ++i) sparce_table_b_[i][0] = b_[i]; + for (size_t j = 1; j <= log(n_); ++j) + for (size_t i = 0; i < k; ++i) { + size_t ind = (1 << (j - 1)) + i; + if (ind >= k) + sparce_table_b_[i][j] = sparce_table_b_[i][j - 1]; + else if (arr_[sparce_table_b_[i][j - 1]] > + arr_[sparce_table_b_[ind][j - 1]]) + sparce_table_b_[i][j] = sparce_table_b_[ind][j - 1]; + else + sparce_table_b_[i][j] = sparce_table_b_[i][j - 1]; + } + // vvv подсчет типов каждого блока + type_ = vector(k, 0); + cur_block = 0; + for (size_t j = 0, i = 0; i < n_ or j < block_size_; ++j, ++i) { + if (j >= block_size_) { + j = 0; + cur_block++; + } + if (j > 0 and (i >= n_ or arr_[i - 1] < arr_[i])) + type_[cur_block] += (1 << (j - 1)); + } + // vvv подсчет позиций минимумов на всех подотрезках для каждого блока + block_min_ = vector>>( + k, vector>(block_size_, vector(block_size_, -1))); + for (size_t i = 0; i < k; ++i) { + size_t t = type_[i]; + if (block_min_[t][0][0] == -1) + // ^^^ если там записано, что-то отличное от -1, то значит, мы уже + // ^ посчитали ответ для такого типа отрезков + for (size_t l = 0; l < block_size_; ++l) { + block_min_[t][l][l] = l; + for (size_t r = l + 1; r < block_size_; ++r) { + block_min_[t][l][r] = block_min_[t][l][r - 1]; + if (i * block_size_ + r <= n_ and + arr_[i * block_size_ + block_min_[t][l][r]] > + arr_[i * block_size_ + r]) + block_min_[t][l][r] = r; + } + } + } + } + T blockRmq(size_t block_num, size_t l, size_t r) { + return block_min_[type_[block_num]][l][r] + block_num * block_size_; + } +}; + +#endif \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..fe5ae2d 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,43 @@ + #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "lca_tree.tpp" + +using namespace std; + +// алгоритм не делает проверку на дурака! должны подаваться только валидные +// деревья + +TEST(Lca, test1) { + vector> list = {{1, 2}, {3, 4}, {5, 6}, {}, {7, 8}, + {}, {}, {}, {}}; + LcaTree t(list, 0); + + EXPECT_EQ(t.lca(6, 2), 2); + EXPECT_EQ(t.lca(0, 1), 0); + EXPECT_EQ(t.lca(3, 8), 1); + EXPECT_EQ(t.lca(7, 5), 0); } + +TEST(Lca, test2) { + vector> list = {{1}, {2, 4}, {3}, {}, {5, 6}, {}, {}}; + LcaTree t(list, 0); + + EXPECT_EQ(t.lca(0, 3), 0); + EXPECT_EQ(t.lca(1, 2), 1); + EXPECT_EQ(t.lca(3, 4), 1); + EXPECT_EQ(t.lca(6, 5), 4); + EXPECT_EQ(t.lca(3, 5), 1); +} + +TEST(Lca, test3) { + vector> list = {{3}, {}, {}, {1, 2, 4}, {5}, {}}; + LcaTree t(list, 0); + + EXPECT_EQ(t.lca(4, 2), 3); + EXPECT_EQ(t.lca(0, 5), 0); + EXPECT_EQ(t.lca(1, 2), 3); + EXPECT_EQ(t.lca(5, 1), 3); + EXPECT_EQ(t.lca(5, 0), 0); +} \ No newline at end of file