From e68f2dffcce157b42adeeb0f9a2ecc2ca59a52aa Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sat, 7 Sep 2024 20:19:33 +0000 Subject: [PATCH 01/17] task_01 done --- lib/src/graph.h | 28 +++++++++++++++++++++ task_01/src/main.cpp | 3 --- task_01/src/test.cpp | 46 +++++++++++++++++++++++++++++++++-- task_01/src/topology_sort.cpp | 20 +++++++++++++++ task_01/src/topology_sort.h | 1 + 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 lib/src/graph.h delete mode 100644 task_01/src/main.cpp create mode 100644 task_01/src/topology_sort.cpp create mode 100644 task_01/src/topology_sort.h diff --git a/lib/src/graph.h b/lib/src/graph.h new file mode 100644 index 0000000..c940b31 --- /dev/null +++ b/lib/src/graph.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +class Graph { + private: + int vertices_number; + std::list* adjacency_list; + + public: + Graph(int number) { + if (number <= 0) throw std::logic_error("number must be positive!"); + vertices_number = number; + adjacency_list = new std::list[vertices_number + 1]; + } + void AddEdge(int first_verticle, int second_verticle) { + if (first_verticle < 0 || first_verticle > vertices_number || + second_verticle < 0 || second_verticle > vertices_number) + throw std::logic_error("such node does not exist"); + if (first_verticle == second_verticle) + throw std::logic_error("graph must be acyclic!"); + adjacency_list[first_verticle].push_back(second_verticle); + } + void TopologySortStep(int current_vertice, bool visited_vertices[], + std::list& list); + std::list TopologySort(); +}; \ No newline at end of file diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_01/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..7641f74 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,47 @@ #include +#include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(TopologySort, test1) { + Graph g(6); + EXPECT_THROW(g.AddEdge(5, 5), std::logic_error); +} + +TEST(TopologySort, test2) { + EXPECT_THROW(Graph g(-5), std::logic_error); + EXPECT_THROW(Graph g(0), std::logic_error); +} + +TEST(TopologySort, test3) { + Graph g(2); + EXPECT_THROW(g.AddEdge(5, 6), std::logic_error); +} + +TEST(TopologySort, test4) { + Graph g(6); + g.AddEdge(5, 2); + g.AddEdge(5, 0); + g.AddEdge(4, 0); + g.AddEdge(4, 1); + g.AddEdge(2, 3); + g.AddEdge(3, 1); + ASSERT_EQ(g.TopologySort(), std::list({5, 4, 2, 3, 1, 0})); +} + +TEST(TopologySort, test5) { + Graph g(15); + g.AddEdge(10, 3); + g.AddEdge(3, 10); + g.AddEdge(10, 14); + g.AddEdge(14, 2); + g.AddEdge(5, 3); + g.AddEdge(3, 5); + g.AddEdge(1, 2); + g.AddEdge(2, 14); + g.AddEdge(14, 1); + g.AddEdge(1, 4); + g.AddEdge(11, 15); + g.AddEdge(15, 5); + + ASSERT_EQ(g.TopologySort(), std::list({13, 12, 11, 15, 9, 8, 7, 6, 3, 5, + 10, 1, 4, 2, 14, 0})); } \ 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..d0bae16 --- /dev/null +++ b/task_01/src/topology_sort.cpp @@ -0,0 +1,20 @@ +#include "topology_sort.h" + +void Graph::TopologySortStep(int current_vertice, bool visited_vertices[], + std::list& list) { + visited_vertices[current_vertice] = true; + for (std::list::iterator i = adjacency_list[current_vertice].begin(); + i != adjacency_list[current_vertice].end(); i++) { + if (!visited_vertices[*i]) TopologySortStep(*i, visited_vertices, list); + } + list.push_front(current_vertice); +} + +std::list Graph::TopologySort() { + std::list list; + bool* visited_vertices = new bool[vertices_number]; + for (int i = 0; i < vertices_number; i++) { + if (!visited_vertices[i]) TopologySortStep(i, visited_vertices, list); + } + return list; +} \ No newline at end of file diff --git a/task_01/src/topology_sort.h b/task_01/src/topology_sort.h new file mode 100644 index 0000000..e9c34f7 --- /dev/null +++ b/task_01/src/topology_sort.h @@ -0,0 +1 @@ +#include \ No newline at end of file From 2f35a069539e389f0c1b04774ac4690fed4727af Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sat, 21 Sep 2024 11:38:46 +0000 Subject: [PATCH 02/17] task_04 done --- lib/src/graph.h | 49 ++++++++++++++++++++++++++++++++++++++++++++ task_04/src/algo.cpp | 1 + task_04/src/main.cpp | 3 --- task_04/src/test.cpp | 40 +++++++++++++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 task_04/src/algo.cpp delete mode 100644 task_04/src/main.cpp diff --git a/lib/src/graph.h b/lib/src/graph.h index c940b31..89a020b 100644 --- a/lib/src/graph.h +++ b/lib/src/graph.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include class Graph { private: @@ -25,4 +27,51 @@ class Graph { void TopologySortStep(int current_vertice, bool visited_vertices[], std::list& list); std::list TopologySort(); +}; + +class Weighted_Graph { + private: + std::vector> table; + int vertices_number; + + public: + Weighted_Graph(std::vector> table_) { + if (table_.empty()) + throw std::logic_error( + "the graph was not created because the input table is empty"); + for (int i = 0; i < table_.size(); i++) + if (table_[i].size() != table_.size()) + throw std::logic_error( + "the graph was not created because the input table is incorrect"); + table = table_; + vertices_number = table.size(); + } + + int MinDistance(std::vector distances, bool is_shortest[]) { + int min_distance = 2 ^ 31 - 1, min_index; + for (int i = 0; i < vertices_number; i++) + if (!is_shortest[i] && distances[i] < min_distance) + min_distance = distances[i], min_index = i; + return min_index; + }; + std::vector Dijkstra_algo(int source) { + source -= 1; + std::vector distances; + bool is_shortest[vertices_number]; + for (int i = 0; i < vertices_number; i++) { + distances.push_back(std::pow(2, 31) - 1); + is_shortest[i] = false; + } + distances[source] = 0; + for (int i = 0; i < vertices_number - 1; i++) { + int min_distance = MinDistance(distances, is_shortest); + is_shortest[min_distance] = true; + for (int j = 0; j < vertices_number; j++) + if (!is_shortest[j] && table[min_distance][j] && + distances[j] != (2 ^ 31 - 1) && + distances[min_distance] + table[min_distance][j] < distances[j]) + distances[j] = distances[min_distance] + table[min_distance][j]; + } + return distances; + } }; \ No newline at end of file diff --git a/task_04/src/algo.cpp b/task_04/src/algo.cpp new file mode 100644 index 0000000..e9c34f7 --- /dev/null +++ b/task_04/src/algo.cpp @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/task_04/src/main.cpp b/task_04/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_04/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..a2e9bee 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,40 @@ - +#include #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(TopologySort, Simple1) { + std::vector> table = { + {0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, + {0, 8, 0, 7, 0, 4, 0, 0, 2}, {0, 0, 7, 0, 9, 14, 0, 0, 0}, + {0, 0, 0, 9, 0, 10, 0, 0, 0}, {0, 0, 4, 14, 10, 0, 2, 0, 0}, + {0, 0, 0, 0, 0, 2, 0, 1, 6}, {8, 11, 0, 0, 0, 0, 1, 0, 7}, + {0, 0, 2, 0, 0, 0, 6, 7, 0}}; + Weighted_Graph graph(table); + ASSERT_EQ(graph.Dijkstra_algo(1), + std::vector({0, 4, 12, 19, 21, 11, 9, 8, 14})); + ASSERT_EQ(graph.Dijkstra_algo(3), + std::vector({12, 8, 0, 7, 14, 4, 6, 7, 2})); +} + +TEST(TopologySort, Simple2) { + std::vector> table = { + {0, 7, 9, 0, 0, 14}, {7, 0, 10, 15, 0, 0}, {9, 10, 0, 11, 0, 2}, + {0, 15, 11, 0, 6, 0}, {0, 0, 0, 6, 0, 9}, {14, 0, 2, 0, 9, 0}}; + Weighted_Graph graph(table); + ASSERT_EQ(graph.Dijkstra_algo(1), std::vector({0, 7, 9, 20, 20, 11})); + ASSERT_EQ(graph.Dijkstra_algo(5), std::vector({20, 21, 11, 6, 0, 9})); +} + +TEST(TopologySort, Simple3) { + std::vector> table = {{1, 2, 3}, {1, 2, 3, 4}}; + EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); +} + +TEST(TopologySort, Simple4) { + std::vector> table = {{}, {}, {}}; + EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); } + +TEST(TopologySort, Simple5) { + std::vector> table = {}; + EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); +} \ No newline at end of file From 8c7d4b0b2052c007ad1481de8c8250b32fc92d4d Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Tue, 1 Oct 2024 14:28:18 +0000 Subject: [PATCH 03/17] graph update --- lib/src/graph.h | 56 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/lib/src/graph.h b/lib/src/graph.h index 89a020b..2ab92b5 100644 --- a/lib/src/graph.h +++ b/lib/src/graph.h @@ -1,10 +1,13 @@ #pragma once #include -#include #include #include +#include + +using std::vector; +template class Graph { private: int vertices_number; @@ -31,11 +34,11 @@ class Graph { class Weighted_Graph { private: - std::vector> table; + vector> table; int vertices_number; public: - Weighted_Graph(std::vector> table_) { + Weighted_Graph(vector> table_) { if (table_.empty()) throw std::logic_error( "the graph was not created because the input table is empty"); @@ -47,16 +50,16 @@ class Weighted_Graph { vertices_number = table.size(); } - int MinDistance(std::vector distances, bool is_shortest[]) { + int MinDistance(vector distances, bool is_shortest[]) { int min_distance = 2 ^ 31 - 1, min_index; for (int i = 0; i < vertices_number; i++) if (!is_shortest[i] && distances[i] < min_distance) min_distance = distances[i], min_index = i; return min_index; }; - std::vector Dijkstra_algo(int source) { + vector Dijkstra_algo(int source) { source -= 1; - std::vector distances; + vector distances; bool is_shortest[vertices_number]; for (int i = 0; i < vertices_number; i++) { distances.push_back(std::pow(2, 31) - 1); @@ -74,4 +77,45 @@ class Weighted_Graph { } return distances; } + vector BellmanFord_Algorithm(int source) { + vector dist(source + 1, pow(2,31)); + dist[source] = 0; + + vector> edges_with_extra(table); + for (int i = 0; i < source; ++i) { + edges_with_extra.push_back({source, i, 0}); + } + + for (int i = 0; i < source; ++i) { + for (const auto& edge : edges_with_extra) { + if (dist[edge[0]] != pow(2,31) && dist[edge[0]] + edge[2] < dist[edge[1]]) { + dist[edge[1]] = dist[edge[0]] + edge[2]; + } + } + } + return vector(dist.begin(), dist.begin() + V); +} +vector> JohnsonAlgorithm(const vector>& graph) { + int V = graph.size(); + vector> edges; + + for (int i = 0; i < V; ++i) + for (int j = 0; j < V; ++j) + if (graph[i][j] != 0) + edges.push_back({i, j, graph[i][j]}); + + vector altered_weights = BellmanFord_Algorithm(edges, V); + vector> altered_graph(V, vector(V, 0)); + + for (int i = 0; i < V; ++i) + for (int j = 0; j < V; ++j) + if (graph[i][j] != 0) + altered_graph[i][j] = graph[i][j] + altered_weights[i] - altered_weights[j]; + + return altered_graph; + + // for (int source = 0; source < V; ++source) { + // Dijkstra_Algorithm(graph, altered_graph, source); + // } +} }; \ No newline at end of file From 329ed607619f791e669d0235bbaf2abe62ab9569 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Tue, 1 Oct 2024 15:56:04 +0000 Subject: [PATCH 04/17] fix errors --- lib/src/{graph.h => graph.hpp} | 74 ++++++++++++++++++++-------------- lib/src/util.cpp | 2 +- task_01/src/test.cpp | 15 +++---- task_01/src/topology_sort.cpp | 21 +--------- task_01/src/topology_sort.h | 1 - task_04/src/algo.cpp | 2 +- task_04/src/test.cpp | 3 +- 7 files changed, 56 insertions(+), 62 deletions(-) rename lib/src/{graph.h => graph.hpp} (63%) delete mode 100644 task_01/src/topology_sort.h diff --git a/lib/src/graph.h b/lib/src/graph.hpp similarity index 63% rename from lib/src/graph.h rename to lib/src/graph.hpp index 2ab92b5..7bffef1 100644 --- a/lib/src/graph.h +++ b/lib/src/graph.hpp @@ -1,23 +1,23 @@ #pragma once #include +#include #include #include -#include using std::vector; -template +template class Graph { private: int vertices_number; - std::list* adjacency_list; + std::list* adjacency_list; public: Graph(int number) { if (number <= 0) throw std::logic_error("number must be positive!"); vertices_number = number; - adjacency_list = new std::list[vertices_number + 1]; + adjacency_list = new std::list[vertices_number + 1]; } void AddEdge(int first_verticle, int second_verticle) { if (first_verticle < 0 || first_verticle > vertices_number || @@ -28,8 +28,23 @@ class Graph { adjacency_list[first_verticle].push_back(second_verticle); } void TopologySortStep(int current_vertice, bool visited_vertices[], - std::list& list); - std::list TopologySort(); + std::list& list) { + visited_vertices[current_vertice] = true; + for (typename std::list::iterator i = + adjacency_list[current_vertice].begin(); + i != adjacency_list[current_vertice].end(); i++) { + if (!visited_vertices[*i]) TopologySortStep(*i, visited_vertices, list); + } + list.push_front(current_vertice); + } + std::list TopologySort() { + std::list list; + bool* visited_vertices = new bool[vertices_number]; + for (int i = 0; i < vertices_number; i++) { + if (!visited_vertices[i]) TopologySortStep(i, visited_vertices, list); + } + return list; + } }; class Weighted_Graph { @@ -78,44 +93,41 @@ class Weighted_Graph { return distances; } vector BellmanFord_Algorithm(int source) { - vector dist(source + 1, pow(2,31)); + vector dist(source + 1, pow(2, 31)); dist[source] = 0; vector> edges_with_extra(table); for (int i = 0; i < source; ++i) { - edges_with_extra.push_back({source, i, 0}); + edges_with_extra.push_back({source, i, 0}); } for (int i = 0; i < source; ++i) { - for (const auto& edge : edges_with_extra) { - if (dist[edge[0]] != pow(2,31) && dist[edge[0]] + edge[2] < dist[edge[1]]) { - dist[edge[1]] = dist[edge[0]] + edge[2]; - } + for (const auto& edge : edges_with_extra) { + if (dist[edge[0]] != pow(2, 31) && + dist[edge[0]] + edge[2] < dist[edge[1]]) { + dist[edge[1]] = dist[edge[0]] + edge[2]; } + } } - return vector(dist.begin(), dist.begin() + V); -} -vector> JohnsonAlgorithm(const vector>& graph) { + return vector(dist.begin(), dist.begin() + source); + } + vector> JohnsonAlgorithm(const vector>& graph) { int V = graph.size(); vector> edges; - - for (int i = 0; i < V; ++i) - for (int j = 0; j < V; ++j) - if (graph[i][j] != 0) - edges.push_back({i, j, graph[i][j]}); - - vector altered_weights = BellmanFord_Algorithm(edges, V); + + for (int i = 0; i < V; ++i) + for (int j = 0; j < V; ++j) + if (graph[i][j] != 0) edges.push_back({i, j, graph[i][j]}); + + vector altered_weights = BellmanFord_Algorithm(V); vector> altered_graph(V, vector(V, 0)); - for (int i = 0; i < V; ++i) - for (int j = 0; j < V; ++j) - if (graph[i][j] != 0) - altered_graph[i][j] = graph[i][j] + altered_weights[i] - altered_weights[j]; + for (int i = 0; i < V; ++i) + for (int j = 0; j < V; ++j) + if (graph[i][j] != 0) + altered_graph[i][j] = + graph[i][j] + altered_weights[i] - altered_weights[j]; return altered_graph; - - // for (int source = 0; source < V; ++source) { - // Dijkstra_Algorithm(graph, altered_graph, source); - // } -} + } }; \ No newline at end of file diff --git a/lib/src/util.cpp b/lib/src/util.cpp index 81e15bd..bd3c48f 100644 --- a/lib/src/util.cpp +++ b/lib/src/util.cpp @@ -1 +1 @@ -#include "util.hpp" +#include "util.hpp" \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 7641f74..0ddf480 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,23 +1,24 @@ #include -#include + +#include TEST(TopologySort, test1) { - Graph g(6); + Graph g(6); EXPECT_THROW(g.AddEdge(5, 5), std::logic_error); } TEST(TopologySort, test2) { - EXPECT_THROW(Graph g(-5), std::logic_error); - EXPECT_THROW(Graph g(0), std::logic_error); + EXPECT_THROW(Graph g(-5), std::logic_error); + EXPECT_THROW(Graph g(0), std::logic_error); } TEST(TopologySort, test3) { - Graph g(2); + Graph g(2); EXPECT_THROW(g.AddEdge(5, 6), std::logic_error); } TEST(TopologySort, test4) { - Graph g(6); + Graph g(6); g.AddEdge(5, 2); g.AddEdge(5, 0); g.AddEdge(4, 0); @@ -28,7 +29,7 @@ TEST(TopologySort, test4) { } TEST(TopologySort, test5) { - Graph g(15); + Graph g(15); g.AddEdge(10, 3); g.AddEdge(3, 10); g.AddEdge(10, 14); diff --git a/task_01/src/topology_sort.cpp b/task_01/src/topology_sort.cpp index d0bae16..08d4d88 100644 --- a/task_01/src/topology_sort.cpp +++ b/task_01/src/topology_sort.cpp @@ -1,20 +1 @@ -#include "topology_sort.h" - -void Graph::TopologySortStep(int current_vertice, bool visited_vertices[], - std::list& list) { - visited_vertices[current_vertice] = true; - for (std::list::iterator i = adjacency_list[current_vertice].begin(); - i != adjacency_list[current_vertice].end(); i++) { - if (!visited_vertices[*i]) TopologySortStep(*i, visited_vertices, list); - } - list.push_front(current_vertice); -} - -std::list Graph::TopologySort() { - std::list list; - bool* visited_vertices = new bool[vertices_number]; - for (int i = 0; i < vertices_number; i++) { - if (!visited_vertices[i]) TopologySortStep(i, visited_vertices, list); - } - return list; -} \ No newline at end of file +// nothing \ No newline at end of file diff --git a/task_01/src/topology_sort.h b/task_01/src/topology_sort.h deleted file mode 100644 index e9c34f7..0000000 --- a/task_01/src/topology_sort.h +++ /dev/null @@ -1 +0,0 @@ -#include \ No newline at end of file diff --git a/task_04/src/algo.cpp b/task_04/src/algo.cpp index e9c34f7..08d4d88 100644 --- a/task_04/src/algo.cpp +++ b/task_04/src/algo.cpp @@ -1 +1 @@ -#include \ No newline at end of file +// nothing \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index a2e9bee..8c7293e 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,7 @@ -#include #include +#include + TEST(TopologySort, Simple1) { std::vector> table = { {0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, From 6e15ed6d6e7dfac310b8cde190a0e44fcc84c82c Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Tue, 1 Oct 2024 20:33:37 +0000 Subject: [PATCH 05/17] task_02 done --- lib/src/graph.hpp | 72 +++++++++++++++++++++++++++++ task_02/src/algo.cpp | 1 + task_02/src/main.cpp | 3 -- task_02/src/stack.cpp | 21 --------- task_02/src/stack.hpp | 23 --------- task_02/src/test.cpp | 105 +++++++++++++++++++++++++++--------------- 6 files changed, 141 insertions(+), 84 deletions(-) create mode 100644 task_02/src/algo.cpp delete mode 100644 task_02/src/main.cpp delete mode 100644 task_02/src/stack.cpp delete mode 100644 task_02/src/stack.hpp diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 7bffef1..26b7c69 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -130,4 +130,76 @@ class Weighted_Graph { return altered_graph; } +}; + +template +class BridgeGraph { + private: + int vertices_number; + std::list* adjacency_list; + vector tin, low; + vector visited; + vector> bridges; + vector articulation_points; + + void dfs(int v, int p, int& timer) { + visited[v] = true; + tin[v] = low[v] = timer++; + int children = 0; + + for (int to : adjacency_list[v]) { + if (to == p) continue; + if (visited[to]) { + low[v] = std::min(low[v], tin[to]); + } else { + dfs(to, v, timer); + low[v] = std::min(low[v], low[to]); + + if (low[to] > tin[v]) bridges.push_back({v, to}); + if (low[to] >= tin[v] && p != -1) { + if (articulation_points.empty()) { + articulation_points.push_back(v); + } else if (articulation_points.back() != v) { + articulation_points.push_back(v); + } + } + ++children; + } + } + + if (p == -1 && children > 1) articulation_points.push_back(v); + } + + public: + BridgeGraph(int number) { + if (number <= 0) throw std::logic_error("number must be positive!"); + vertices_number = number; + adjacency_list = new std::list[vertices_number + 1]; + } + + void AddEdge(int first_verticle, int second_verticle) { + if (first_verticle < 0 || first_verticle > vertices_number || + second_verticle < 0 || second_verticle > vertices_number) + throw std::logic_error("such node does not exist"); + if (first_verticle == second_verticle) + throw std::logic_error("graph must be acyclic!"); + adjacency_list[first_verticle].push_back(second_verticle); + adjacency_list[second_verticle].push_back(first_verticle); + } + + void FindBridgesAndArticulationPoints() { + int timer = 0; + tin.assign(vertices_number + 1, -1); + low.assign(vertices_number + 1, -1); + visited.assign(vertices_number + 1, false); + bridges.clear(); + articulation_points.clear(); + + for (int i = 0; i <= vertices_number; ++i) { + if (!visited[i]) dfs(i, -1, timer); + } + } + + vector> GiveBridges() { return bridges; } + vector GivePoints() { return articulation_points; } }; \ No newline at end of file diff --git a/task_02/src/algo.cpp b/task_02/src/algo.cpp new file mode 100644 index 0000000..08d4d88 --- /dev/null +++ b/task_02/src/algo.cpp @@ -0,0 +1 @@ +// nothing \ No newline at end of file diff --git a/task_02/src/main.cpp b/task_02/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_02/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { 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..849e694 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,42 +1,73 @@ #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 [] +#include + +using std::pair; + +TEST(StackTest, test1) { + BridgeGraph g(5); + + g.AddEdge(1, 2); + g.AddEdge(1, 3); + g.AddEdge(3, 4); + g.AddEdge(3, 5); + g.AddEdge(4, 5); + + g.FindBridgesAndArticulationPoints(); + + vector> bridges({{1, 2}, {1, 3}}); + ASSERT_EQ(g.GiveBridges(), bridges); + vector articulation_points({3, 1}); + ASSERT_EQ(g.GivePoints(), articulation_points); +} + +TEST(StackTest, test2) { + BridgeGraph g(5); + + g.AddEdge(1, 5); + g.AddEdge(1, 2); + g.AddEdge(1, 3); + g.AddEdge(2, 4); + g.AddEdge(2, 5); + g.AddEdge(3, 5); + + g.FindBridgesAndArticulationPoints(); + + vector> bridges({{2, 4}}); + ASSERT_EQ(g.GiveBridges(), bridges); + vector articulation_points({2}); + ASSERT_EQ(g.GivePoints(), articulation_points); } -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 [] -} \ No newline at end of file +TEST(StackTest, test3) { + BridgeGraph g(8); + + g.AddEdge(1, 2); + g.AddEdge(1, 8); + g.AddEdge(2, 6); + g.AddEdge(2, 8); + g.AddEdge(3, 4); + g.AddEdge(3, 5); + g.AddEdge(3, 6); + g.AddEdge(6, 7); + g.AddEdge(7, 8); + + g.FindBridgesAndArticulationPoints(); + + vector> bridges({{3, 4}, {3, 5}, {6, 3}}); + ASSERT_EQ(g.GiveBridges(), bridges); + vector articulation_points({3, 6}); + ASSERT_EQ(g.GivePoints(), articulation_points); +} + +TEST(StackTest, test4) { + EXPECT_THROW(BridgeGraph g(-5), std::logic_error); + EXPECT_THROW(BridgeGraph g(0), std::logic_error); +} + +TEST(StackTest, test5) { + BridgeGraph g(2); + EXPECT_THROW(g.AddEdge(5, 6), std::logic_error); + EXPECT_THROW(g.AddEdge(5, -4), std::logic_error); +} From 227e9715f56b742bf7796ebd44db1ba759677be9 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Wed, 2 Oct 2024 13:00:20 +0000 Subject: [PATCH 06/17] task_03 done --- lib/src/graph.hpp | 82 +++++++++++++++++------------------ task_03/src/algo.cpp | 1 + task_03/src/main.cpp | 3 -- task_03/src/test.cpp | 70 ++++++++++++++++++++++++++++-- task_03/src/topology_sort.cpp | 1 - task_03/src/topology_sort.hpp | 1 - 6 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 task_03/src/algo.cpp delete mode 100644 task_03/src/main.cpp delete mode 100644 task_03/src/topology_sort.cpp delete mode 100644 task_03/src/topology_sort.hpp diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 26b7c69..66d2f0c 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -66,70 +66,70 @@ class Weighted_Graph { } int MinDistance(vector distances, bool is_shortest[]) { - int min_distance = 2 ^ 31 - 1, min_index; + int min_distance = std::numeric_limits::max(), min_index; for (int i = 0; i < vertices_number; i++) if (!is_shortest[i] && distances[i] < min_distance) min_distance = distances[i], min_index = i; return min_index; }; - vector Dijkstra_algo(int source) { - source -= 1; - vector distances; - bool is_shortest[vertices_number]; - for (int i = 0; i < vertices_number; i++) { - distances.push_back(std::pow(2, 31) - 1); - is_shortest[i] = false; - } - distances[source] = 0; - for (int i = 0; i < vertices_number - 1; i++) { - int min_distance = MinDistance(distances, is_shortest); - is_shortest[min_distance] = true; - for (int j = 0; j < vertices_number; j++) - if (!is_shortest[j] && table[min_distance][j] && - distances[j] != (2 ^ 31 - 1) && - distances[min_distance] + table[min_distance][j] < distances[j]) - distances[j] = distances[min_distance] + table[min_distance][j]; - } - return distances; - } - vector BellmanFord_Algorithm(int source) { - vector dist(source + 1, pow(2, 31)); - dist[source] = 0; + vector BellmanFord_Algorithm(const vector>& edges) { + vector dist(vertices_number + 1, std::numeric_limits::max()); + dist[vertices_number] = 0; - vector> edges_with_extra(table); - for (int i = 0; i < source; ++i) { - edges_with_extra.push_back({source, i, 0}); + vector> edges_with_extra = edges; + for (int i = 0; i < vertices_number; ++i) { + edges_with_extra.push_back({vertices_number, i, 0}); } - for (int i = 0; i < source; ++i) { + for (int i = 0; i < vertices_number; ++i) { for (const auto& edge : edges_with_extra) { - if (dist[edge[0]] != pow(2, 31) && + if (dist[edge[0]] != std::numeric_limits::max() && dist[edge[0]] + edge[2] < dist[edge[1]]) { dist[edge[1]] = dist[edge[0]] + edge[2]; } } } - return vector(dist.begin(), dist.begin() + source); + return vector(dist.begin(), dist.begin() + vertices_number); } - vector> JohnsonAlgorithm(const vector>& graph) { - int V = graph.size(); + vector> JohnsonAlgorithm() { vector> edges; - for (int i = 0; i < V; ++i) - for (int j = 0; j < V; ++j) - if (graph[i][j] != 0) edges.push_back({i, j, graph[i][j]}); + for (int i = 0; i < vertices_number; ++i) + for (int j = 0; j < vertices_number; ++j) + if (table[i][j] != 0) edges.push_back({i, j, table[i][j]}); - vector altered_weights = BellmanFord_Algorithm(V); - vector> altered_graph(V, vector(V, 0)); + vector altered_weights = BellmanFord_Algorithm(edges); + vector> altered_graph(vertices_number, + vector(vertices_number, 0)); - for (int i = 0; i < V; ++i) - for (int j = 0; j < V; ++j) - if (graph[i][j] != 0) + for (int i = 0; i < vertices_number; ++i) + for (int j = 0; j < vertices_number; ++j) + if (table[i][j] != 0) altered_graph[i][j] = - graph[i][j] + altered_weights[i] - altered_weights[j]; + table[i][j] + altered_weights[i] - altered_weights[j]; return altered_graph; } + vector Dijkstra_algo(int source) { + source -= 1; + vector distances; + bool is_shortest[vertices_number]; + for (int i = 0; i < vertices_number; i++) { + distances.push_back(std::numeric_limits::max()); + is_shortest[i] = false; + } + distances[source] = 0; + for (int i = 0; i < vertices_number - 1; i++) { + int min_distance = MinDistance(distances, is_shortest); + is_shortest[min_distance] = true; + for (int j = 0; j < vertices_number; j++) + if (!is_shortest[j] && table[min_distance][j] && + distances[j] != std::numeric_limits::max() && + distances[min_distance] + table[min_distance][j] < distances[j]) + distances[j] = distances[min_distance] + table[min_distance][j]; + } + return distances; + } }; template diff --git a/task_03/src/algo.cpp b/task_03/src/algo.cpp new file mode 100644 index 0000000..08d4d88 --- /dev/null +++ b/task_03/src/algo.cpp @@ -0,0 +1 @@ +// nothing \ No newline at end of file diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_03/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..c42f7c3 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,72 @@ #include -#include "topology_sort.hpp" +#include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(TopologySort, test1) { + vector> g = { + {0, -5, 2, 3}, {0, 0, 4, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}}; + + Weighted_Graph wg(g); + vector> shortest_paths( + {{0, 0, 3, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}); + + ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); +} + +TEST(TopologySort, test2) { + vector> g = {{0, 1, 0, 5, 1}, + {0, 0, 0, 0, 0}, + {0, 0, -3, 0, 5}, + {0, 1, 7, 0, 1}, + {1, 0, 0, 4, 0}}; + + Weighted_Graph wg(g); + vector> shortest_paths({{0, -3, 0, 2, 2}, + {0, 0, 0, 0, 0}, + {0, 0, -3, 0, 0}, + {0, 0, 16, 0, 5}, + {0, 0, 0, 0, 0}}); + + ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); +} + +TEST(TopologySort, test3) { + vector> g = {{0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}; + + Weighted_Graph wg(g); + vector> shortest_paths({{0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}); + + ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); } + +TEST(TopologySort, test4) { + vector> g = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }; + + EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); +} + +TEST(TopologySort, test5) { + vector> g = {}; + + EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); +} + +TEST(TopologySort, test6) { + vector> g = {{}, {}, {1, 3, 4}}; + + EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); +} \ No newline at end of file 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 From 87c9f3a4bd9c23cf8c15490c914b53d899c36262 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Wed, 2 Oct 2024 14:12:36 +0000 Subject: [PATCH 07/17] task_05 done --- task_05/src/algo.cpp | 1 + task_05/src/algo.hpp | 61 ++++++++++++++++++++++++++++++++++++++++++++ task_05/src/main.cpp | 3 --- task_05/src/test.cpp | 53 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 task_05/src/algo.cpp create mode 100644 task_05/src/algo.hpp delete mode 100644 task_05/src/main.cpp diff --git a/task_05/src/algo.cpp b/task_05/src/algo.cpp new file mode 100644 index 0000000..08d4d88 --- /dev/null +++ b/task_05/src/algo.cpp @@ -0,0 +1 @@ +// nothing \ No newline at end of file diff --git a/task_05/src/algo.hpp b/task_05/src/algo.hpp new file mode 100644 index 0000000..4c58fe0 --- /dev/null +++ b/task_05/src/algo.hpp @@ -0,0 +1,61 @@ +#include +#include +#include + +using std::vector; + +template +struct RMQ { + vector data; + int size; + static const int block_size = 30; + vector masks, table; + + int Operation(int x, int y) { return data[x] < data[y] ? x : y; } + int LeastSignificantBit(int x) { return x & -x; } + int MostSignificantBitIndex(int x) { return 31 - __builtin_clz(x); } + int Small(int r, int size = block_size) { + int dist_from_r = MostSignificantBitIndex(masks[r] & ((1 << size) - 1)); + return r - dist_from_r; + } + + RMQ(const vector& v) + : data(v), + size(data.size()), + masks(size), + table((size / block_size) * 32) { + int current_mask = 0; + for (int i = 0; i < size; i++) { + current_mask = (current_mask << 1) & ((1 << block_size) - 1); + while (current_mask > 0 && + Operation(i, i - MostSignificantBitIndex( + LeastSignificantBit(current_mask))) == i) { + current_mask ^= LeastSignificantBit(current_mask); + } + current_mask |= 1; + masks[i] = current_mask; + } + for (int i = 0; i < size / block_size; i++) + table[i] = Small(block_size * i + block_size - 1); + for (int j = 1; (1 << j) <= size / block_size; j++) + for (int i = 0; i + (1 << j) <= size / block_size; i++) + table[size / block_size * j + i] = + Operation(table[size / block_size * (j - 1) + i], + table[size / block_size * (j - 1) + i + (1 << (j - 1))]); + } + + T Query(int l, int r) { + if (l < 0 || r >= data.size()) + throw std::out_of_range("incorrect boundaries!"); + if (r - l + 1 <= block_size) return data[Small(r, r - l + 1)]; + int ans = Operation(Small(l + block_size - 1), Small(r)); + int x = l / block_size + 1, y = r / block_size - 1; + if (x <= y) { + int j = MostSignificantBitIndex(y - x + 1); + ans = Operation( + ans, Operation(table[size / block_size * j + x], + table[size / block_size * j + y - (1 << j) + 1])); + } + return data[ans]; + } +}; diff --git a/task_05/src/main.cpp b/task_05/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_05/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..e6d3354 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,55 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "algo.hpp" + +TEST(TopologySort, test1) { + vector data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, 6, 8, 4, 0, 3, + 6, 7, 2, 5, 9, 10, 12, 14, 13, 15, 18, 17, 16, 19, 20}; + RMQ rmq(data); + ASSERT_EQ(rmq.Query(0, 4), 1); + ASSERT_EQ(rmq.Query(5, 10), 1); + ASSERT_EQ(rmq.Query(10, 20), 0); + ASSERT_EQ(rmq.Query(0, 29), 0); + ASSERT_EQ(rmq.Query(15, 25), 2); +} + +TEST(TopologySort, test2) { + vector data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + RMQ rmq(data); + ASSERT_EQ(rmq.Query(0, 10), 0); + ASSERT_EQ(rmq.Query(5, 15), 0); + ASSERT_EQ(rmq.Query(10, 20), 0); + ASSERT_EQ(rmq.Query(0, 20), 0); + ASSERT_EQ(rmq.Query(3, 7), 3); +} + +TEST(TopologySort, test3) { + vector data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; + RMQ rmq(data); + ASSERT_EQ(rmq.Query(0, 10), 5); + ASSERT_EQ(rmq.Query(5, 15), 5); + ASSERT_EQ(rmq.Query(10, 20), 5); + ASSERT_EQ(rmq.Query(0, 20), 5); + ASSERT_EQ(rmq.Query(3, 7), 5); } + +TEST(TopologySort, test4) { + vector data = {}; + RMQ rmq(data); + EXPECT_THROW(rmq.Query(1, 3), std::out_of_range); +} + +TEST(TopologySort, test5) { + vector data = {1, 2, 3}; + RMQ rmq(data); + EXPECT_THROW(rmq.Query(0, 3), std::out_of_range); +} + +TEST(TopologySort, test6) { + vector data = {1, 2, 3}; + RMQ rmq(data); + EXPECT_THROW(rmq.Query(-1, 2), std::out_of_range); +} \ No newline at end of file From dc91c7322a03068c1a3591a959b601c0632b7c8d Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Wed, 2 Oct 2024 14:15:58 +0000 Subject: [PATCH 08/17] added discription for the RMQ algo --- task_05/src/algo.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/task_05/src/algo.hpp b/task_05/src/algo.hpp index 4c58fe0..5bba529 100644 --- a/task_05/src/algo.hpp +++ b/task_05/src/algo.hpp @@ -4,6 +4,11 @@ using std::vector; +/* +Один из самых быстрых реализаций алгоритма RMQ +Выдает запрос за O(1), предобработка структуры данных - O(n) +*/ + template struct RMQ { vector data; From d430b291da1cfef7e0680eadbbd1755f182086a3 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Wed, 2 Oct 2024 15:12:07 +0000 Subject: [PATCH 09/17] task_06 done --- task_06/src/algo.cpp | 1 + task_06/src/algo.hpp | 62 ++++++++++++++++++++++++++ task_06/src/main.cpp | 3 -- task_06/src/test.cpp | 104 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 task_06/src/algo.cpp create mode 100644 task_06/src/algo.hpp delete mode 100644 task_06/src/main.cpp diff --git a/task_06/src/algo.cpp b/task_06/src/algo.cpp new file mode 100644 index 0000000..08d4d88 --- /dev/null +++ b/task_06/src/algo.cpp @@ -0,0 +1 @@ +// nothing \ No newline at end of file diff --git a/task_06/src/algo.hpp b/task_06/src/algo.hpp new file mode 100644 index 0000000..935c714 --- /dev/null +++ b/task_06/src/algo.hpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +using std::vector; + +/* +Алгоритм Фарака-Колтона и Бендера +Выдает запрос за O(1), предобработка структуры данных - O(n) +*/ + +class LCA { + public: + LCA(const vector>& tree, int root) { + if (tree.empty()) throw std::logic_error("the input vector is empty!"); + for (const auto& i : tree) + if (i.empty()) throw std::logic_error("vertex vector is empty"); + n = tree.size(); + int log_n = log2(n) + 1; + up.assign(n, vector(log_n, -1)); + depth.resize(n); + Dfs(tree, root, root); + } + + int Query(int u, int v) { + if (u < 0 || v >= n) throw std::out_of_range("incorrect boundaries!"); + if (depth[u] < depth[v]) std::swap(u, v); + int log_n = up[0].size(); + for (int i = log_n - 1; i >= 0; i--) { + if (depth[u] - (1 << i) >= depth[v]) u = up[u][i]; + } + if (u == v) return u; + for (int i = log_n - 1; i >= 0; i--) { + if (up[u][i] != up[v][i]) { + u = up[u][i]; + v = up[v][i]; + } + } + return up[u][0]; + } + + private: + vector> up; + vector depth; + int n; + + void Dfs(const vector>& tree, int v, int p) { + up[v][0] = p; + for (int i = 1; i < up[v].size(); i++) { + if (up[v][i - 1] != -1) { + up[v][i] = up[up[v][i - 1]][i - 1]; + } + } + for (int u : tree[v]) { + if (u != p) { + depth[u] = depth[v] + 1; + Dfs(tree, u, v); + } + } + } +}; diff --git a/task_06/src/main.cpp b/task_06/src/main.cpp deleted file mode 100644 index 0e4393b..0000000 --- a/task_06/src/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { return 0; } diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..773f3ba 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,104 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "algo.hpp" + +TEST(TopologySort, test1) { + vector> tree(10); + tree[0] = {1, 2}; + tree[1] = {0, 3, 4}; + tree[2] = {0, 5, 6}; + tree[3] = {1, 7}; + tree[4] = {1, 8, 9}; + tree[5] = {2}; + tree[6] = {2}; + tree[7] = {3}; + tree[8] = {4}; + tree[9] = {4}; + + LCA lca(tree, 0); + + ASSERT_EQ(lca.Query(3, 4), 1); + ASSERT_EQ(lca.Query(7, 8), 1); + ASSERT_EQ(lca.Query(5, 6), 2); + ASSERT_EQ(lca.Query(7, 9), 1); + ASSERT_EQ(lca.Query(8, 9), 4); } + +TEST(TopologySort, test2) { + vector> tree(7); + tree[0] = {1, 2}; + tree[1] = {0, 3, 4}; + tree[2] = {0, 5, 6}; + tree[3] = {1}; + tree[4] = {1}; + tree[5] = {2}; + tree[6] = {2}; + + LCA lca(tree, 0); + + ASSERT_EQ(lca.Query(3, 4), 1); + ASSERT_EQ(lca.Query(3, 5), 0); + ASSERT_EQ(lca.Query(4, 6), 0); + ASSERT_EQ(lca.Query(5, 6), 2); + ASSERT_EQ(lca.Query(1, 2), 0); +} + +TEST(TopologySort, test3) { + vector> tree(9); + tree[0] = {1, 2}; + tree[1] = {0, 3, 4}; + tree[2] = {0, 5, 6}; + tree[3] = {1, 7}; + tree[4] = {1, 8}; + tree[5] = {2}; + tree[6] = {2}; + tree[7] = {3}; + tree[8] = {4}; + + LCA lca(tree, 0); + + ASSERT_EQ(lca.Query(3, 4), 1); + ASSERT_EQ(lca.Query(7, 8), 1); + ASSERT_EQ(lca.Query(5, 6), 2); + ASSERT_EQ(lca.Query(7, 3), 3); + ASSERT_EQ(lca.Query(8, 4), 4); +} + +TEST(TopologySort, test4) { + vector> tree(4); + tree[0] = {1, 2}; + tree[1] = {0, 3}; + tree[2] = {0}; + tree[3] = {1}; + + LCA lca(tree, 0); + + EXPECT_THROW(lca.Query(-1, 2), std::out_of_range); +} + +TEST(TopologySort, test5) { + vector> tree(4); + tree[0] = {1, 2}; + tree[1] = {0, 3}; + tree[2] = {0}; + tree[3] = {1}; + + LCA lca(tree, 0); + + EXPECT_THROW(lca.Query(0, 4), std::out_of_range); +} + +TEST(TopologySort, test6) { + vector> tree(4); + tree[0] = {1, 2}; + tree[1] = {0, 3}; + tree[2] = {0}; + + EXPECT_THROW(LCA lca(tree, 0), std::logic_error); +} + +TEST(TopologySort, test7) { + vector> tree; + + EXPECT_THROW(LCA lca(tree, 0), std::logic_error); +} \ No newline at end of file From 7b8da7cfb084cc9215c2d0024061a9c84f9239d0 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Wed, 2 Oct 2024 17:02:22 +0000 Subject: [PATCH 10/17] fix names and bug --- lib/src/graph.hpp | 17 ++++++++--------- task_02/src/test.cpp | 10 +++++----- task_03/src/test.cpp | 12 ++++++------ task_04/src/test.cpp | 10 +++++----- task_05/src/{algo.cpp => rmq.cpp} | 0 task_05/src/{algo.hpp => rmq.hpp} | 0 task_05/src/test.cpp | 14 +++++++------- task_06/src/{algo.cpp => lca.cpp} | 0 task_06/src/{algo.hpp => lca.hpp} | 0 task_06/src/test.cpp | 16 ++++++++-------- 10 files changed, 39 insertions(+), 40 deletions(-) rename task_05/src/{algo.cpp => rmq.cpp} (100%) rename task_05/src/{algo.hpp => rmq.hpp} (100%) rename task_06/src/{algo.cpp => lca.cpp} (100%) rename task_06/src/{algo.hpp => lca.hpp} (100%) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 66d2f0c..0a42144 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -64,14 +64,6 @@ class Weighted_Graph { table = table_; vertices_number = table.size(); } - - int MinDistance(vector distances, bool is_shortest[]) { - int min_distance = std::numeric_limits::max(), min_index; - for (int i = 0; i < vertices_number; i++) - if (!is_shortest[i] && distances[i] < min_distance) - min_distance = distances[i], min_index = i; - return min_index; - }; vector BellmanFord_Algorithm(const vector>& edges) { vector dist(vertices_number + 1, std::numeric_limits::max()); dist[vertices_number] = 0; @@ -110,6 +102,13 @@ class Weighted_Graph { return altered_graph; } + int MinDistance(vector distances, bool is_shortest[]) { + int min_distance = std::numeric_limits::max(), min_index; + for (int i = 0; i < vertices_number; i++) + if (!is_shortest[i] && distances[i] < min_distance) + min_distance = distances[i], min_index = i; + return min_index; + }; vector Dijkstra_algo(int source) { source -= 1; vector distances; @@ -124,7 +123,7 @@ class Weighted_Graph { is_shortest[min_distance] = true; for (int j = 0; j < vertices_number; j++) if (!is_shortest[j] && table[min_distance][j] && - distances[j] != std::numeric_limits::max() && + distances[j] != (std::numeric_limits::max() - 1) && distances[min_distance] + table[min_distance][j] < distances[j]) distances[j] = distances[min_distance] + table[min_distance][j]; } diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 849e694..1a96fff 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -5,7 +5,7 @@ using std::pair; -TEST(StackTest, test1) { +TEST(BridgeGraphTest, test1) { BridgeGraph g(5); g.AddEdge(1, 2); @@ -22,7 +22,7 @@ TEST(StackTest, test1) { ASSERT_EQ(g.GivePoints(), articulation_points); } -TEST(StackTest, test2) { +TEST(BridgeGraphTest, test2) { BridgeGraph g(5); g.AddEdge(1, 5); @@ -40,7 +40,7 @@ TEST(StackTest, test2) { ASSERT_EQ(g.GivePoints(), articulation_points); } -TEST(StackTest, test3) { +TEST(BridgeGraphTest, test3) { BridgeGraph g(8); g.AddEdge(1, 2); @@ -61,12 +61,12 @@ TEST(StackTest, test3) { ASSERT_EQ(g.GivePoints(), articulation_points); } -TEST(StackTest, test4) { +TEST(BridgeGraphTest, test4) { EXPECT_THROW(BridgeGraph g(-5), std::logic_error); EXPECT_THROW(BridgeGraph g(0), std::logic_error); } -TEST(StackTest, test5) { +TEST(BridgeGraphTest, test5) { BridgeGraph g(2); EXPECT_THROW(g.AddEdge(5, 6), std::logic_error); EXPECT_THROW(g.AddEdge(5, -4), std::logic_error); diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index c42f7c3..461bbe5 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -3,7 +3,7 @@ #include -TEST(TopologySort, test1) { +TEST(JohnsonAlgorithm, test1) { vector> g = { {0, -5, 2, 3}, {0, 0, 4, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}}; @@ -14,7 +14,7 @@ TEST(TopologySort, test1) { ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); } -TEST(TopologySort, test2) { +TEST(JohnsonAlgorithm, test2) { vector> g = {{0, 1, 0, 5, 1}, {0, 0, 0, 0, 0}, {0, 0, -3, 0, 5}, @@ -31,7 +31,7 @@ TEST(TopologySort, test2) { ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); } -TEST(TopologySort, test3) { +TEST(JohnsonAlgorithm, test3) { vector> g = {{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, @@ -48,7 +48,7 @@ TEST(TopologySort, test3) { ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); } -TEST(TopologySort, test4) { +TEST(JohnsonAlgorithm, test4) { vector> g = { {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, @@ -59,13 +59,13 @@ TEST(TopologySort, test4) { EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); } -TEST(TopologySort, test5) { +TEST(JohnsonAlgorithm, test5) { vector> g = {}; EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); } -TEST(TopologySort, test6) { +TEST(JohnsonAlgorithm, test6) { vector> g = {{}, {}, {1, 3, 4}}; EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 8c7293e..6b8447e 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -2,7 +2,7 @@ #include -TEST(TopologySort, Simple1) { +TEST(DijkstraAlgorithm, Simple1) { std::vector> table = { {0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, {0, 8, 0, 7, 0, 4, 0, 0, 2}, {0, 0, 7, 0, 9, 14, 0, 0, 0}, @@ -16,7 +16,7 @@ TEST(TopologySort, Simple1) { std::vector({12, 8, 0, 7, 14, 4, 6, 7, 2})); } -TEST(TopologySort, Simple2) { +TEST(DijkstraAlgorithm, Simple2) { std::vector> table = { {0, 7, 9, 0, 0, 14}, {7, 0, 10, 15, 0, 0}, {9, 10, 0, 11, 0, 2}, {0, 15, 11, 0, 6, 0}, {0, 0, 0, 6, 0, 9}, {14, 0, 2, 0, 9, 0}}; @@ -25,17 +25,17 @@ TEST(TopologySort, Simple2) { ASSERT_EQ(graph.Dijkstra_algo(5), std::vector({20, 21, 11, 6, 0, 9})); } -TEST(TopologySort, Simple3) { +TEST(DijkstraAlgorithm, Simple3) { std::vector> table = {{1, 2, 3}, {1, 2, 3, 4}}; EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); } -TEST(TopologySort, Simple4) { +TEST(DijkstraAlgorithm, Simple4) { std::vector> table = {{}, {}, {}}; EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); } -TEST(TopologySort, Simple5) { +TEST(DijkstraAlgorithm, Simple5) { std::vector> table = {}; EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); } \ No newline at end of file diff --git a/task_05/src/algo.cpp b/task_05/src/rmq.cpp similarity index 100% rename from task_05/src/algo.cpp rename to task_05/src/rmq.cpp diff --git a/task_05/src/algo.hpp b/task_05/src/rmq.hpp similarity index 100% rename from task_05/src/algo.hpp rename to task_05/src/rmq.hpp diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index e6d3354..e35cce8 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,9 +1,9 @@ #include -#include "algo.hpp" +#include "rmq.hpp" -TEST(TopologySort, test1) { +TEST(RMQTest, test1) { vector data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, 6, 8, 4, 0, 3, 6, 7, 2, 5, 9, 10, 12, 14, 13, 15, 18, 17, 16, 19, 20}; RMQ rmq(data); @@ -14,7 +14,7 @@ TEST(TopologySort, test1) { ASSERT_EQ(rmq.Query(15, 25), 2); } -TEST(TopologySort, test2) { +TEST(RMQTest, test2) { vector data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; RMQ rmq(data); @@ -25,7 +25,7 @@ TEST(TopologySort, test2) { ASSERT_EQ(rmq.Query(3, 7), 3); } -TEST(TopologySort, test3) { +TEST(RMQTest, test3) { vector data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; RMQ rmq(data); @@ -36,19 +36,19 @@ TEST(TopologySort, test3) { ASSERT_EQ(rmq.Query(3, 7), 5); } -TEST(TopologySort, test4) { +TEST(RMQTest, test4) { vector data = {}; RMQ rmq(data); EXPECT_THROW(rmq.Query(1, 3), std::out_of_range); } -TEST(TopologySort, test5) { +TEST(RMQTest, test5) { vector data = {1, 2, 3}; RMQ rmq(data); EXPECT_THROW(rmq.Query(0, 3), std::out_of_range); } -TEST(TopologySort, test6) { +TEST(RMQTest, test6) { vector data = {1, 2, 3}; RMQ rmq(data); EXPECT_THROW(rmq.Query(-1, 2), std::out_of_range); diff --git a/task_06/src/algo.cpp b/task_06/src/lca.cpp similarity index 100% rename from task_06/src/algo.cpp rename to task_06/src/lca.cpp diff --git a/task_06/src/algo.hpp b/task_06/src/lca.hpp similarity index 100% rename from task_06/src/algo.hpp rename to task_06/src/lca.hpp diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 773f3ba..9a0fbcb 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,8 +1,8 @@ #include -#include "algo.hpp" +#include "lca.hpp" -TEST(TopologySort, test1) { +TEST(LCATest, test1) { vector> tree(10); tree[0] = {1, 2}; tree[1] = {0, 3, 4}; @@ -24,7 +24,7 @@ TEST(TopologySort, test1) { ASSERT_EQ(lca.Query(8, 9), 4); } -TEST(TopologySort, test2) { +TEST(LCATest, test2) { vector> tree(7); tree[0] = {1, 2}; tree[1] = {0, 3, 4}; @@ -43,7 +43,7 @@ TEST(TopologySort, test2) { ASSERT_EQ(lca.Query(1, 2), 0); } -TEST(TopologySort, test3) { +TEST(LCATest, test3) { vector> tree(9); tree[0] = {1, 2}; tree[1] = {0, 3, 4}; @@ -64,7 +64,7 @@ TEST(TopologySort, test3) { ASSERT_EQ(lca.Query(8, 4), 4); } -TEST(TopologySort, test4) { +TEST(LCATest, test4) { vector> tree(4); tree[0] = {1, 2}; tree[1] = {0, 3}; @@ -76,7 +76,7 @@ TEST(TopologySort, test4) { EXPECT_THROW(lca.Query(-1, 2), std::out_of_range); } -TEST(TopologySort, test5) { +TEST(LCATest, test5) { vector> tree(4); tree[0] = {1, 2}; tree[1] = {0, 3}; @@ -88,7 +88,7 @@ TEST(TopologySort, test5) { EXPECT_THROW(lca.Query(0, 4), std::out_of_range); } -TEST(TopologySort, test6) { +TEST(LCATest, test6) { vector> tree(4); tree[0] = {1, 2}; tree[1] = {0, 3}; @@ -97,7 +97,7 @@ TEST(TopologySort, test6) { EXPECT_THROW(LCA lca(tree, 0), std::logic_error); } -TEST(TopologySort, test7) { +TEST(LCATest, test7) { vector> tree; EXPECT_THROW(LCA lca(tree, 0), std::logic_error); From 2907581e72a9f413bddd1772336f30a4990c557f Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sun, 3 Nov 2024 20:35:50 +0000 Subject: [PATCH 11/17] fix all --- lib/src/graph.hpp | 282 +++++++++++++++++++++++++------------------ task_01/src/test.cpp | 35 +++--- task_03/src/test.cpp | 138 +++++++++++++-------- task_04/src/test.cpp | 104 +++++++++++----- task_05/src/rmq.cpp | 2 +- task_05/src/rmq.hpp | 8 +- task_06/src/lca.cpp | 48 +++++++- task_06/src/lca.hpp | 48 +------- 8 files changed, 401 insertions(+), 264 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 0a42144..c8e63c5 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,132 +1,179 @@ #pragma once #include +#include #include +#include +#include #include #include +using std::list; +using std::pair; using std::vector; +const int INF = std::numeric_limits::max(); + template class Graph { private: - int vertices_number; - std::list* adjacency_list; + size_t vertices_number_; + std::unique_ptr[]> adjacency_list_; public: - Graph(int number) { + Graph(size_t number) { if (number <= 0) throw std::logic_error("number must be positive!"); - vertices_number = number; - adjacency_list = new std::list[vertices_number + 1]; + vertices_number_ = number; + adjacency_list_ = std::make_unique[]>(vertices_number_ + 1); } - void AddEdge(int first_verticle, int second_verticle) { - if (first_verticle < 0 || first_verticle > vertices_number || - second_verticle < 0 || second_verticle > vertices_number) + + void AddEdge(size_t first_verticle, size_t second_verticle) { + if (first_verticle < 1 || first_verticle > vertices_number_ || + second_verticle < 1 || second_verticle > vertices_number_) throw std::logic_error("such node does not exist"); if (first_verticle == second_verticle) throw std::logic_error("graph must be acyclic!"); - adjacency_list[first_verticle].push_back(second_verticle); + adjacency_list_[first_verticle].push_back(second_verticle); } - void TopologySortStep(int current_vertice, bool visited_vertices[], - std::list& list) { + + void TopologySortStep(int current_vertice, vector& visited_vertices, + list& list) { visited_vertices[current_vertice] = true; - for (typename std::list::iterator i = - adjacency_list[current_vertice].begin(); - i != adjacency_list[current_vertice].end(); i++) { - if (!visited_vertices[*i]) TopologySortStep(*i, visited_vertices, list); + for (const auto& neighbor : adjacency_list_[current_vertice]) { + if (!visited_vertices[neighbor]) { + TopologySortStep(neighbor, visited_vertices, list); + } } list.push_front(current_vertice); } - std::list TopologySort() { - std::list list; - bool* visited_vertices = new bool[vertices_number]; - for (int i = 0; i < vertices_number; i++) { - if (!visited_vertices[i]) TopologySortStep(i, visited_vertices, list); + + list TopologySort() { + list list; + vector visited_vertices(vertices_number_ + 1, false); + for (size_t i = 1; i <= vertices_number_; i++) { + if (!visited_vertices[i]) { + TopologySortStep(i, visited_vertices, list); + } } return list; } }; -class Weighted_Graph { +class WeightedGraph { private: - vector> table; - int vertices_number; + vector> table_; + size_t vertices_number_; + + void CheckNegativeCycle(const vector& distances) { + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + throw std::logic_error("Graph contains a negative weight cycle"); + } + } + } + } + } + + bool RelaxEdges(vector& distances) { + bool updated = false; + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + distances[v] = distances[u] + table_[u][v]; + updated = true; + } + } + } + } + return updated; + } + + vector BellmanFord(int start) { + vector distances(vertices_number_, INF); + distances[start] = 0; + + for (size_t i = 0; i < vertices_number_ - 1; ++i) { + RelaxEdges(distances); + } + + CheckNegativeCycle(distances); + return distances; + } public: - Weighted_Graph(vector> table_) { + WeightedGraph(vector>&& table) + : table_(std::move(table)), vertices_number_(table_.size()) { if (table_.empty()) throw std::logic_error( "the graph was not created because the input table is empty"); - for (int i = 0; i < table_.size(); i++) + for (size_t i = 0; i < table_.size(); i++) if (table_[i].size() != table_.size()) throw std::logic_error( "the graph was not created because the input table is incorrect"); - table = table_; - vertices_number = table.size(); } - vector BellmanFord_Algorithm(const vector>& edges) { - vector dist(vertices_number + 1, std::numeric_limits::max()); - dist[vertices_number] = 0; - vector> edges_with_extra = edges; - for (int i = 0; i < vertices_number; ++i) { - edges_with_extra.push_back({vertices_number, i, 0}); - } + vector Dijkstra(int start) { + vector distances(vertices_number_, INF); + distances[start] = 0; + + std::priority_queue, vector>, std::greater<>> + pq; + pq.push({0, start}); - for (int i = 0; i < vertices_number; ++i) { - for (const auto& edge : edges_with_extra) { - if (dist[edge[0]] != std::numeric_limits::max() && - dist[edge[0]] + edge[2] < dist[edge[1]]) { - dist[edge[1]] = dist[edge[0]] + edge[2]; + while (!pq.empty()) { + int u = pq.top().second; + int dist_u = pq.top().first; + pq.pop(); + + if (dist_u > distances[u]) continue; + + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + int new_dist = distances[u] + table_[u][v]; + if (new_dist < distances[v]) { + distances[v] = new_dist; + pq.push({new_dist, v}); + } } } } - return vector(dist.begin(), dist.begin() + vertices_number); + return distances; } - vector> JohnsonAlgorithm() { - vector> edges; - - for (int i = 0; i < vertices_number; ++i) - for (int j = 0; j < vertices_number; ++j) - if (table[i][j] != 0) edges.push_back({i, j, table[i][j]}); - vector altered_weights = BellmanFord_Algorithm(edges); - vector> altered_graph(vertices_number, - vector(vertices_number, 0)); + vector> Johnson() { + vector h(vertices_number_ + 1, 0); - for (int i = 0; i < vertices_number; ++i) - for (int j = 0; j < vertices_number; ++j) - if (table[i][j] != 0) - altered_graph[i][j] = - table[i][j] + altered_weights[i] - altered_weights[j]; + table_.push_back(vector(vertices_number_, 0)); + try { + h = BellmanFord(vertices_number_); + } catch (const std::logic_error&) { + throw std::logic_error( + "Graph contains a negative weight cycle, Johnson's algorithm cannot " + "be applied"); + } + table_.pop_back(); - return altered_graph; - } - int MinDistance(vector distances, bool is_shortest[]) { - int min_distance = std::numeric_limits::max(), min_index; - for (int i = 0; i < vertices_number; i++) - if (!is_shortest[i] && distances[i] < min_distance) - min_distance = distances[i], min_index = i; - return min_index; - }; - vector Dijkstra_algo(int source) { - source -= 1; - vector distances; - bool is_shortest[vertices_number]; - for (int i = 0; i < vertices_number; i++) { - distances.push_back(std::numeric_limits::max()); - is_shortest[i] = false; + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF) { + table_[u][v] += h[u] - h[v]; + } + } } - distances[source] = 0; - for (int i = 0; i < vertices_number - 1; i++) { - int min_distance = MinDistance(distances, is_shortest); - is_shortest[min_distance] = true; - for (int j = 0; j < vertices_number; j++) - if (!is_shortest[j] && table[min_distance][j] && - distances[j] != (std::numeric_limits::max() - 1) && - distances[min_distance] + table[min_distance][j] < distances[j]) - distances[j] = distances[min_distance] + table[min_distance][j]; + + vector> distances(vertices_number_); + for (size_t u = 0; u < vertices_number_; ++u) { + distances[u] = Dijkstra(u); + for (size_t v = 0; v < vertices_number_; ++v) { + if (distances[u][v] != INF) { + distances[u][v] += h[v] - h[u]; + } + } } + return distances; } }; @@ -134,71 +181,72 @@ class Weighted_Graph { template class BridgeGraph { private: - int vertices_number; - std::list* adjacency_list; - vector tin, low; - vector visited; - vector> bridges; - vector articulation_points; + size_t vertices_number_; + list* adjacency_list_; + vector tin_, low_; + vector visited_; + vector> bridges_; + vector articulation_points_; void dfs(int v, int p, int& timer) { - visited[v] = true; - tin[v] = low[v] = timer++; + visited_[v] = true; + tin_[v] = low_[v] = timer++; int children = 0; - for (int to : adjacency_list[v]) { + for (int to : adjacency_list_[v]) { if (to == p) continue; - if (visited[to]) { - low[v] = std::min(low[v], tin[to]); + if (visited_[to]) { + low_[v] = std::min(low_[v], tin_[to]); } else { dfs(to, v, timer); - low[v] = std::min(low[v], low[to]); - - if (low[to] > tin[v]) bridges.push_back({v, to}); - if (low[to] >= tin[v] && p != -1) { - if (articulation_points.empty()) { - articulation_points.push_back(v); - } else if (articulation_points.back() != v) { - articulation_points.push_back(v); + low_[v] = std::min(low_[v], low_[to]); + + if (low_[to] > tin_[v]) bridges_.push_back({v, to}); + if (articulation_points_.empty()) { + if (low_[to] >= tin_[v] && p != -1) { + if (articulation_points_.empty() || + articulation_points_.back() != v) { + articulation_points_.push_back(v); + } } } ++children; } } - if (p == -1 && children > 1) articulation_points.push_back(v); + if (p == -1 && children > 1) articulation_points_.push_back(v); } public: - BridgeGraph(int number) { + BridgeGraph(size_t number) { if (number <= 0) throw std::logic_error("number must be positive!"); - vertices_number = number; - adjacency_list = new std::list[vertices_number + 1]; + vertices_number_ = number; + adjacency_list_ = new list[vertices_number_ + 1]; } - void AddEdge(int first_verticle, int second_verticle) { - if (first_verticle < 0 || first_verticle > vertices_number || - second_verticle < 0 || second_verticle > vertices_number) + void AddEdge(size_t first_verticle, size_t second_verticle) { + if (first_verticle < 0 || first_verticle > vertices_number_ || + second_verticle < 0 || second_verticle > vertices_number_) throw std::logic_error("such node does not exist"); if (first_verticle == second_verticle) throw std::logic_error("graph must be acyclic!"); - adjacency_list[first_verticle].push_back(second_verticle); - adjacency_list[second_verticle].push_back(first_verticle); + adjacency_list_[first_verticle].push_back(second_verticle); + adjacency_list_[second_verticle].push_back(first_verticle); } void FindBridgesAndArticulationPoints() { int timer = 0; - tin.assign(vertices_number + 1, -1); - low.assign(vertices_number + 1, -1); - visited.assign(vertices_number + 1, false); - bridges.clear(); - articulation_points.clear(); - - for (int i = 0; i <= vertices_number; ++i) { - if (!visited[i]) dfs(i, -1, timer); + tin_.assign(vertices_number_ + 1, -1); + low_.assign(vertices_number_ + 1, -1); + visited_.assign(vertices_number_ + 1, false); + bridges_.clear(); + articulation_points_.clear(); + + for (size_t i = 0; i <= vertices_number_; ++i) { + if (!visited_[i]) dfs(i, -1, timer); } } - vector> GiveBridges() { return bridges; } - vector GivePoints() { return articulation_points; } + vector> GiveBridges() { return bridges_; } + vector GivePoints() { return articulation_points_; } }; \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 0ddf480..78f1f5c 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -18,31 +18,28 @@ TEST(TopologySort, test3) { } TEST(TopologySort, test4) { - Graph g(6); + Graph g(5); g.AddEdge(5, 2); - g.AddEdge(5, 0); - g.AddEdge(4, 0); + g.AddEdge(5, 1); g.AddEdge(4, 1); + g.AddEdge(4, 5); g.AddEdge(2, 3); g.AddEdge(3, 1); - ASSERT_EQ(g.TopologySort(), std::list({5, 4, 2, 3, 1, 0})); + ASSERT_EQ(g.TopologySort(), std::list({4, 5, 2, 3, 1})); } TEST(TopologySort, test5) { - Graph g(15); - g.AddEdge(10, 3); - g.AddEdge(3, 10); - g.AddEdge(10, 14); - g.AddEdge(14, 2); - g.AddEdge(5, 3); - g.AddEdge(3, 5); - g.AddEdge(1, 2); - g.AddEdge(2, 14); - g.AddEdge(14, 1); - g.AddEdge(1, 4); - g.AddEdge(11, 15); - g.AddEdge(15, 5); + Graph g(12); + g.AddEdge(1, 2); + g.AddEdge(2, 3); + g.AddEdge(3, 4); + g.AddEdge(4, 5); + g.AddEdge(5, 6); + g.AddEdge(6, 7); + g.AddEdge(7, 8); + g.AddEdge(7, 8); + g.AddEdge(7, 8); + g.AddEdge(7, 8); - ASSERT_EQ(g.TopologySort(), std::list({13, 12, 11, 15, 9, 8, 7, 6, 3, 5, - 10, 1, 4, 2, 14, 0})); + ASSERT_EQ(g.TopologySort(), std::list({12, 11, 10, 9, 1, 2, 3, 4, 5, 6, 7, 8 })); } \ No newline at end of file diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index 461bbe5..a16c98c 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -3,70 +3,106 @@ #include -TEST(JohnsonAlgorithm, test1) { - vector> g = { - {0, -5, 2, 3}, {0, 0, 4, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}}; +TEST(JohnsonAlgorithmTest, PositiveWeights) { + vector> graph = {{0, 3, INF, INF, INF}, + {INF, 0, 1, INF, 10}, + {4, INF, 0, 2, INF}, + {INF, INF, INF, 0, 1}, + {INF, INF, INF, INF, 0}}; + vector> expected_distances = {{0, 3, 4, 6, 7}, + {5, 0, 1, 3, 4}, + {4, 7, 0, 2, 3}, + {INF, INF, INF, 0, 1}, + {INF, INF, INF, INF, 0}}; + + WeightedGraph wg(std::move(graph)); + ASSERT_EQ(wg.Johnson(), expected_distances); +} + +TEST(JohnsonAlgorithmTest, NegativeWeights) { + vector> graph = {{0, -1, 4, INF, INF}, + {INF, 0, 3, 2, 2}, + {INF, INF, 0, INF, INF}, + {INF, 1, 5, 0, INF}, + {INF, INF, INF, -3, 0}}; + vector> expected_distances = {{0, -1, 2, -2, 1}, + {INF, 0, 3, -1, 2}, + {INF, INF, 0, INF, INF}, + {INF, 1, 4, 0, 3}, + {INF, -2, 1, -3, 0}}; + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); +} - Weighted_Graph wg(g); - vector> shortest_paths( - {{0, 0, 3, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}); +TEST(JohnsonAlgorithmTest, NegativeCycle) { + vector> graph = {{0, 1, INF, INF}, + {INF, 0, -1, INF}, + {INF, INF, 0, -1}, + {-1, INF, INF, 0}}; - ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); + WeightedGraph wg(std::move(graph)); + EXPECT_THROW(wg.Johnson();, std::logic_error); } -TEST(JohnsonAlgorithm, test2) { - vector> g = {{0, 1, 0, 5, 1}, - {0, 0, 0, 0, 0}, - {0, 0, -3, 0, 5}, - {0, 1, 7, 0, 1}, - {1, 0, 0, 4, 0}}; - - Weighted_Graph wg(g); - vector> shortest_paths({{0, -3, 0, 2, 2}, - {0, 0, 0, 0, 0}, - {0, 0, -3, 0, 0}, - {0, 0, 16, 0, 5}, - {0, 0, 0, 0, 0}}); - - ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); +TEST(JohnsonAlgorithmTest, PositiveWeightsLargerGraph) { + vector> graph = { + {0, 10, INF, INF, INF, 5}, {INF, 0, 1, INF, INF, 2}, + {INF, INF, 0, 4, INF, INF}, {7, INF, 6, 0, 3, INF}, + {INF, INF, 9, 2, 0, INF}, {INF, 3, INF, 9, 2, 0}}; + vector> expected_distances = { + {0, 8, 9, 13, 7, 5}, {INF, 0, 1, 5, 3, 2}, {INF, INF, 0, 4, 6, 7}, + {7, 10, 6, 0, 3, 9}, {9, 12, 8, 2, 0, 10}, {5, 3, 4, 8, 2, 0}}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); +} + +TEST(JohnsonAlgorithmTest, PositiveWeightsDisconnectedGraph) { + vector> graph = { + {0, 3, INF, INF}, {INF, 0, 7, INF}, {INF, INF, 0, 2}, {INF, INF, INF, 0}}; + vector> expected_distances = { + {0, 3, 10, 12}, {INF, 0, 7, 9}, {INF, INF, 0, 2}, {INF, INF, INF, 0}}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); } -TEST(JohnsonAlgorithm, test3) { - vector> g = {{0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}}; - - Weighted_Graph wg(g); - vector> shortest_paths({{0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}}); - - ASSERT_EQ(wg.JohnsonAlgorithm(), shortest_paths); +TEST(JohnsonAlgorithmTest, NegativeWeightsComplexGraph) { + vector> graph = { + {0, 4, INF, INF, INF, INF}, {INF, 0, -2, INF, INF, INF}, + {INF, INF, 0, 3, INF, INF}, {INF, INF, INF, 0, 2, 3}, + {INF, INF, INF, INF, 0, -1}, {INF, INF, INF, INF, INF, 0}}; + vector> expected_distances = { + {0, 4, 2, 5, 7, 6}, {INF, 0, -2, 1, 3, 2}, + {INF, INF, 0, 3, 5, 4}, {INF, INF, INF, 0, 2, 1}, + {INF, INF, INF, INF, 0, -1}, {INF, INF, INF, INF, INF, 0}}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); } -TEST(JohnsonAlgorithm, test4) { - vector> g = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - }; +TEST(JohnsonAlgorithmTest, NegativeAndPositiveWeightsMixed) { + vector> graph = {{0, INF, INF, 1}, + {INF, 0, -3, INF}, + {INF, INF, 0, INF}, + {10, INF, INF, 0}}; + vector> expected_distances = { + {0, 11, 8, 1}, {7, 0, -3, 8}, {INF, INF, 0, INF}, {10, 21, 18, 0}}; - EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); } -TEST(JohnsonAlgorithm, test5) { - vector> g = {}; +TEST(JohnsonAlgorithmTest, SingleVertex) { + vector> graph = {{0}}; + vector> expected_distances = {{0}}; - EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Johnson(), expected_distances); } -TEST(JohnsonAlgorithm, test6) { - vector> g = {{}, {}, {1, 3, 4}}; +TEST(JohnsonAlgorithmTest, EmptyGraph) { + vector> graph; - EXPECT_THROW(Weighted_Graph wg(g), std::logic_error); + EXPECT_THROW(WeightedGraph wg(std::move(graph)), std::logic_error); } \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 6b8447e..b197b8c 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -2,40 +2,88 @@ #include -TEST(DijkstraAlgorithm, Simple1) { - std::vector> table = { - {0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, - {0, 8, 0, 7, 0, 4, 0, 0, 2}, {0, 0, 7, 0, 9, 14, 0, 0, 0}, - {0, 0, 0, 9, 0, 10, 0, 0, 0}, {0, 0, 4, 14, 10, 0, 2, 0, 0}, - {0, 0, 0, 0, 0, 2, 0, 1, 6}, {8, 11, 0, 0, 0, 0, 1, 0, 7}, - {0, 0, 2, 0, 0, 0, 6, 7, 0}}; - Weighted_Graph graph(table); - ASSERT_EQ(graph.Dijkstra_algo(1), - std::vector({0, 4, 12, 19, 21, 11, 9, 8, 14})); - ASSERT_EQ(graph.Dijkstra_algo(3), - std::vector({12, 8, 0, 7, 14, 4, 6, 7, 2})); +TEST(DijkstraAlgorithmTest, PositiveWeights) { + vector> graph = {{0, 10, INF, 30, 100}, + {INF, 0, 50, INF, INF}, + {INF, INF, 0, INF, 10}, + {INF, INF, 20, 0, 60}, + {INF, INF, INF, INF, 0}}; + vector expected_distances = {0, 10, 50, 30, 60}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); +} + +TEST(DijkstraAlgorithmTest, DisconnectedGraph) { + vector> graph = {{0, INF, INF, INF, INF}, + {INF, 0, 15, INF, INF}, + {INF, INF, 0, INF, INF}, + {INF, INF, INF, 0, 5}, + {INF, INF, INF, INF, 0}}; + vector expected_distances = {0, INF, INF, INF, INF}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); +} + +TEST(DijkstraAlgorithmTest, SingleVertex) { + vector> graph = {{0}}; + vector expected_distances = {0}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); } -TEST(DijkstraAlgorithm, Simple2) { - std::vector> table = { - {0, 7, 9, 0, 0, 14}, {7, 0, 10, 15, 0, 0}, {9, 10, 0, 11, 0, 2}, - {0, 15, 11, 0, 6, 0}, {0, 0, 0, 6, 0, 9}, {14, 0, 2, 0, 9, 0}}; - Weighted_Graph graph(table); - ASSERT_EQ(graph.Dijkstra_algo(1), std::vector({0, 7, 9, 20, 20, 11})); - ASSERT_EQ(graph.Dijkstra_algo(5), std::vector({20, 21, 11, 6, 0, 9})); +TEST(DijkstraAlgorithmTest, StartVertexDisconnected) { + vector> graph = {{0, INF, INF, INF}, + {INF, 0, 7, INF}, + {INF, INF, 0, 3}, + {INF, INF, INF, 0}}; + vector expected_distances = {0, INF, INF, INF}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); } -TEST(DijkstraAlgorithm, Simple3) { - std::vector> table = {{1, 2, 3}, {1, 2, 3, 4}}; - EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); +TEST(DijkstraAlgorithmTest, MultiplePaths) { + vector> graph = {{0, 1, 4, INF, INF}, + {INF, 0, 4, 2, 7}, + {INF, INF, 0, 3, INF}, + {INF, INF, INF, 0, 1}, + {INF, INF, INF, INF, 0}}; + vector expected_distances = {0, 1, 4, 3, 4}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); } -TEST(DijkstraAlgorithm, Simple4) { - std::vector> table = {{}, {}, {}}; - EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); +TEST(DijkstraAlgorithmTest, GraphWithSelfLoops) { + vector> graph = { + {0, 10, INF, 5}, {INF, 0, 1, INF}, {INF, INF, 0, 4}, {7, INF, 2, 0}}; + vector expected_distances = {0, 10, 7, 5}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); } -TEST(DijkstraAlgorithm, Simple5) { - std::vector> table = {}; - EXPECT_THROW(Weighted_Graph graph(table), std::logic_error); +TEST(DijkstraAlgorithmTest, LargerGraph) { + vector> graph = { + {0, 3, 1, INF, INF, INF}, {3, 0, 7, 5, 1, INF}, {1, 7, 0, 2, INF, 3}, + {INF, 5, 2, 0, 7, 4}, {INF, 1, INF, 7, 0, 6}, {INF, INF, 3, 4, 6, 0}}; + vector expected_distances = {0, 3, 1, 3, 4, 4}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); +} + +TEST(DijkstraAlgorithmTest, EvenLargerGraph) { + vector> graph = { + {0, 10, INF, INF, INF, 5, INF, INF}, {10, 0, 2, 1, INF, INF, INF, INF}, + {INF, 2, 0, 4, 8, INF, INF, INF}, {INF, 1, 4, 0, 2, INF, INF, INF}, + {INF, INF, 8, 2, 0, 3, 6, INF}, {5, INF, INF, INF, 3, 0, INF, 9}, + {INF, INF, INF, INF, 6, INF, 0, 1}, {INF, INF, INF, INF, INF, 9, 1, 0}}; + vector expected_distances = {0, 10, 12, 10, 8, 5, 14, 14}; + + WeightedGraph wg(std::move(graph)); + EXPECT_EQ(wg.Dijkstra(0), expected_distances); } \ No newline at end of file diff --git a/task_05/src/rmq.cpp b/task_05/src/rmq.cpp index 08d4d88..e9b6a44 100644 --- a/task_05/src/rmq.cpp +++ b/task_05/src/rmq.cpp @@ -1 +1 @@ -// nothing \ No newline at end of file +// nothing diff --git a/task_05/src/rmq.hpp b/task_05/src/rmq.hpp index 5bba529..85ef325 100644 --- a/task_05/src/rmq.hpp +++ b/task_05/src/rmq.hpp @@ -14,7 +14,8 @@ struct RMQ { vector data; int size; static const int block_size = 30; - vector masks, table; + vector masks; + vector table; int Operation(int x, int y) { return data[x] < data[y] ? x : y; } int LeastSignificantBit(int x) { return x & -x; } @@ -30,7 +31,7 @@ struct RMQ { masks(size), table((size / block_size) * 32) { int current_mask = 0; - for (int i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { current_mask = (current_mask << 1) & ((1 << block_size) - 1); while (current_mask > 0 && Operation(i, i - MostSignificantBitIndex( @@ -54,7 +55,8 @@ struct RMQ { throw std::out_of_range("incorrect boundaries!"); if (r - l + 1 <= block_size) return data[Small(r, r - l + 1)]; int ans = Operation(Small(l + block_size - 1), Small(r)); - int x = l / block_size + 1, y = r / block_size - 1; + const int x = l / block_size + 1; + const int y = r / block_size - 1; if (x <= y) { int j = MostSignificantBitIndex(y - x + 1); ans = Operation( diff --git a/task_06/src/lca.cpp b/task_06/src/lca.cpp index 08d4d88..e86470f 100644 --- a/task_06/src/lca.cpp +++ b/task_06/src/lca.cpp @@ -1 +1,47 @@ -// nothing \ No newline at end of file +#include "lca.hpp" + +#include +#include + +LCA::LCA(const vector>& tree, int root) { + if (tree.empty()) throw std::logic_error("the input vector is empty!"); + for (const auto& i : tree) + if (i.empty()) throw std::logic_error("vertex vector is empty"); + n = tree.size(); + int log_n = log2(n) + 1; + up.assign(n, vector(log_n, -1)); + depth.resize(n); + Dfs(tree, root, root); +} + +int LCA::Query(int u, int v) { + if (u < 0 || v >= n) throw std::out_of_range("incorrect boundaries!"); + if (depth[u] < depth[v]) std::swap(u, v); + int log_n = up[0].size(); + for (int i = log_n - 1; i >= 0; i--) { + if (depth[u] - (1 << i) >= depth[v]) u = up[u][i]; + } + if (u == v) return u; + for (int i = log_n - 1; i >= 0; i--) { + if (up[u][i] != up[v][i]) { + u = up[u][i]; + v = up[v][i]; + } + } + return up[u][0]; +} + +void LCA::Dfs(const vector>& tree, int v, int p) { + up[v][0] = p; + for (int i = 1; i < up[v].size(); i++) { + if (up[v][i - 1] != -1) { + up[v][i] = up[up[v][i - 1]][i - 1]; + } + } + for (int u : tree[v]) { + if (u != p) { + depth[u] = depth[v] + 1; + Dfs(tree, u, v); + } + } +} diff --git a/task_06/src/lca.hpp b/task_06/src/lca.hpp index 935c714..43a3c75 100644 --- a/task_06/src/lca.hpp +++ b/task_06/src/lca.hpp @@ -1,62 +1,22 @@ -#include #include -#include #include using std::vector; /* -Алгоритм Фарака-Колтона и Бендера +Алгоритм Фарака-Колтона и Бендера Выдает запрос за O(1), предобработка структуры данных - O(n) */ class LCA { public: - LCA(const vector>& tree, int root) { - if (tree.empty()) throw std::logic_error("the input vector is empty!"); - for (const auto& i : tree) - if (i.empty()) throw std::logic_error("vertex vector is empty"); - n = tree.size(); - int log_n = log2(n) + 1; - up.assign(n, vector(log_n, -1)); - depth.resize(n); - Dfs(tree, root, root); - } - - int Query(int u, int v) { - if (u < 0 || v >= n) throw std::out_of_range("incorrect boundaries!"); - if (depth[u] < depth[v]) std::swap(u, v); - int log_n = up[0].size(); - for (int i = log_n - 1; i >= 0; i--) { - if (depth[u] - (1 << i) >= depth[v]) u = up[u][i]; - } - if (u == v) return u; - for (int i = log_n - 1; i >= 0; i--) { - if (up[u][i] != up[v][i]) { - u = up[u][i]; - v = up[v][i]; - } - } - return up[u][0]; - } + LCA(const vector>& tree, int root); + int Query(int u, int v); private: vector> up; vector depth; int n; - void Dfs(const vector>& tree, int v, int p) { - up[v][0] = p; - for (int i = 1; i < up[v].size(); i++) { - if (up[v][i - 1] != -1) { - up[v][i] = up[up[v][i - 1]][i - 1]; - } - } - for (int u : tree[v]) { - if (u != p) { - depth[u] = depth[v] + 1; - Dfs(tree, u, v); - } - } - } + void Dfs(const vector>& tree, int v, int p); }; From af72e1b3d383a1993e4ff0d46ac03e525e89bb24 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sun, 3 Nov 2024 20:58:11 +0000 Subject: [PATCH 12/17] fix all 2 --- lib/src/graph.hpp | 14 +++++++------- task_05/src/rmq.hpp | 6 +++--- task_05/src/test.cpp | 13 +++++++------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index c8e63c5..b4ca737 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -18,13 +18,13 @@ template class Graph { private: size_t vertices_number_; - std::unique_ptr[]> adjacency_list_; + vector> adjacency_list_; public: Graph(size_t number) { if (number <= 0) throw std::logic_error("number must be positive!"); vertices_number_ = number; - adjacency_list_ = std::make_unique[]>(vertices_number_ + 1); + adjacency_list_.resize(vertices_number_ + 1); } void AddEdge(size_t first_verticle, size_t second_verticle) { @@ -91,7 +91,7 @@ class WeightedGraph { return updated; } - vector BellmanFord(int start) { + vector BellmanFord(size_t start) { vector distances(vertices_number_, INF); distances[start] = 0; @@ -115,7 +115,7 @@ class WeightedGraph { "the graph was not created because the input table is incorrect"); } - vector Dijkstra(int start) { + vector Dijkstra(size_t start) { vector distances(vertices_number_, INF); distances[start] = 0; @@ -124,15 +124,15 @@ class WeightedGraph { pq.push({0, start}); while (!pq.empty()) { - int u = pq.top().second; - int dist_u = pq.top().first; + const int u = pq.top().second; + const int dist_u = pq.top().first; pq.pop(); if (dist_u > distances[u]) continue; for (size_t v = 0; v < vertices_number_; ++v) { if (table_[u][v] != INF && distances[u] != INF) { - int new_dist = distances[u] + table_[u][v]; + const int new_dist = distances[u] + table_[u][v]; if (new_dist < distances[v]) { distances[v] = new_dist; pq.push({new_dist, v}); diff --git a/task_05/src/rmq.hpp b/task_05/src/rmq.hpp index 85ef325..1acd948 100644 --- a/task_05/src/rmq.hpp +++ b/task_05/src/rmq.hpp @@ -12,8 +12,8 @@ using std::vector; template struct RMQ { vector data; - int size; - static const int block_size = 30; + size_t size; + static const size_t block_size = 30; vector masks; vector table; @@ -29,7 +29,7 @@ struct RMQ { : data(v), size(data.size()), masks(size), - table((size / block_size) * 32) { + table((static_cast(size / block_size) * 32)) { int current_mask = 0; for (size_t i = 0; i < size; i++) { current_mask = (current_mask << 1) & ((1 << block_size) - 1); diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index e35cce8..dc3156a 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -4,8 +4,9 @@ #include "rmq.hpp" TEST(RMQTest, test1) { - vector data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, 6, 8, 4, 0, 3, - 6, 7, 2, 5, 9, 10, 12, 14, 13, 15, 18, 17, 16, 19, 20}; + const vector data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, + 6, 8, 4, 0, 3, 6, 7, 2, 5, 9, + 10, 12, 14, 13, 15, 18, 17, 16, 19, 20}; RMQ rmq(data); ASSERT_EQ(rmq.Query(0, 4), 1); ASSERT_EQ(rmq.Query(5, 10), 1); @@ -15,8 +16,8 @@ TEST(RMQTest, test1) { } TEST(RMQTest, test2) { - vector data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + const vector data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; RMQ rmq(data); ASSERT_EQ(rmq.Query(0, 10), 0); ASSERT_EQ(rmq.Query(5, 15), 0); @@ -26,8 +27,8 @@ TEST(RMQTest, test2) { } TEST(RMQTest, test3) { - vector data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; + const vector data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; RMQ rmq(data); ASSERT_EQ(rmq.Query(0, 10), 5); ASSERT_EQ(rmq.Query(5, 15), 5); From 93387bba465a8643b8f48e625c971e718e8328c5 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sun, 3 Nov 2024 21:16:52 +0000 Subject: [PATCH 13/17] fix all 3 --- task_01/src/test.cpp | 23 ++++++++++++----------- task_05/src/rmq.hpp | 8 ++++---- task_05/src/test.cpp | 12 ++++++------ task_06/src/lca.cpp | 10 +++++----- task_06/src/lca.hpp | 2 +- task_06/src/test.cpp | 6 +++--- 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 78f1f5c..d6ad0f0 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -30,16 +30,17 @@ TEST(TopologySort, test4) { TEST(TopologySort, test5) { Graph g(12); - g.AddEdge(1, 2); - g.AddEdge(2, 3); - g.AddEdge(3, 4); - g.AddEdge(4, 5); - g.AddEdge(5, 6); - g.AddEdge(6, 7); - g.AddEdge(7, 8); - g.AddEdge(7, 8); - g.AddEdge(7, 8); - g.AddEdge(7, 8); + g.AddEdge(1, 2); + g.AddEdge(2, 3); + g.AddEdge(3, 4); + g.AddEdge(4, 5); + g.AddEdge(5, 6); + g.AddEdge(6, 7); + g.AddEdge(7, 8); + g.AddEdge(7, 8); + g.AddEdge(7, 8); + g.AddEdge(7, 8); - ASSERT_EQ(g.TopologySort(), std::list({12, 11, 10, 9, 1, 2, 3, 4, 5, 6, 7, 8 })); + ASSERT_EQ(g.TopologySort(), + std::list({12, 11, 10, 9, 1, 2, 3, 4, 5, 6, 7, 8})); } \ No newline at end of file diff --git a/task_05/src/rmq.hpp b/task_05/src/rmq.hpp index 1acd948..348a703 100644 --- a/task_05/src/rmq.hpp +++ b/task_05/src/rmq.hpp @@ -50,15 +50,15 @@ struct RMQ { table[size / block_size * (j - 1) + i + (1 << (j - 1))]); } - T Query(int l, int r) { + T Query(size_t l, size_t r) { if (l < 0 || r >= data.size()) throw std::out_of_range("incorrect boundaries!"); if (r - l + 1 <= block_size) return data[Small(r, r - l + 1)]; int ans = Operation(Small(l + block_size - 1), Small(r)); - const int x = l / block_size + 1; - const int y = r / block_size - 1; + const size_t x = l / block_size + 1; + const size_t y = r / block_size - 1; if (x <= y) { - int j = MostSignificantBitIndex(y - x + 1); + const size_t j = MostSignificantBitIndex(y - x + 1); ans = Operation( ans, Operation(table[size / block_size * j + x], table[size / block_size * j + y - (1 << j) + 1])); diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index dc3156a..f8bbf4d 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -4,7 +4,7 @@ #include "rmq.hpp" TEST(RMQTest, test1) { - const vector data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, + vector const data = {1, 3, 2, 7, 9, 11, 3, 2, 1, 5, 6, 8, 4, 0, 3, 6, 7, 2, 5, 9, 10, 12, 14, 13, 15, 18, 17, 16, 19, 20}; RMQ rmq(data); @@ -16,7 +16,7 @@ TEST(RMQTest, test1) { } TEST(RMQTest, test2) { - const vector data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + vector const data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; RMQ rmq(data); ASSERT_EQ(rmq.Query(0, 10), 0); @@ -27,7 +27,7 @@ TEST(RMQTest, test2) { } TEST(RMQTest, test3) { - const vector data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + vector const data = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; RMQ rmq(data); ASSERT_EQ(rmq.Query(0, 10), 5); @@ -38,19 +38,19 @@ TEST(RMQTest, test3) { } TEST(RMQTest, test4) { - vector data = {}; + vector const data = {}; RMQ rmq(data); EXPECT_THROW(rmq.Query(1, 3), std::out_of_range); } TEST(RMQTest, test5) { - vector data = {1, 2, 3}; + vector const data = {1, 2, 3}; RMQ rmq(data); EXPECT_THROW(rmq.Query(0, 3), std::out_of_range); } TEST(RMQTest, test6) { - vector data = {1, 2, 3}; + vector const data = {1, 2, 3}; RMQ rmq(data); EXPECT_THROW(rmq.Query(-1, 2), std::out_of_range); } \ No newline at end of file diff --git a/task_06/src/lca.cpp b/task_06/src/lca.cpp index e86470f..e75c3e3 100644 --- a/task_06/src/lca.cpp +++ b/task_06/src/lca.cpp @@ -8,7 +8,7 @@ LCA::LCA(const vector>& tree, int root) { for (const auto& i : tree) if (i.empty()) throw std::logic_error("vertex vector is empty"); n = tree.size(); - int log_n = log2(n) + 1; + const int log_n = static_cast(log2(n) + 1); up.assign(n, vector(log_n, -1)); depth.resize(n); Dfs(tree, root, root); @@ -17,12 +17,12 @@ LCA::LCA(const vector>& tree, int root) { int LCA::Query(int u, int v) { if (u < 0 || v >= n) throw std::out_of_range("incorrect boundaries!"); if (depth[u] < depth[v]) std::swap(u, v); - int log_n = up[0].size(); - for (int i = log_n - 1; i >= 0; i--) { + const size_t log_n = up[0].size(); + for (size_t i = log_n - 1; i >= 0; i--) { if (depth[u] - (1 << i) >= depth[v]) u = up[u][i]; } if (u == v) return u; - for (int i = log_n - 1; i >= 0; i--) { + for (size_t i = log_n - 1; i >= 0; i--) { if (up[u][i] != up[v][i]) { u = up[u][i]; v = up[v][i]; @@ -38,7 +38,7 @@ void LCA::Dfs(const vector>& tree, int v, int p) { up[v][i] = up[up[v][i - 1]][i - 1]; } } - for (int u : tree[v]) { + for (const int u : tree[v]) { if (u != p) { depth[u] = depth[v] + 1; Dfs(tree, u, v); diff --git a/task_06/src/lca.hpp b/task_06/src/lca.hpp index 43a3c75..723f971 100644 --- a/task_06/src/lca.hpp +++ b/task_06/src/lca.hpp @@ -16,7 +16,7 @@ class LCA { private: vector> up; vector depth; - int n; + size_t n; void Dfs(const vector>& tree, int v, int p); }; diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 9a0fbcb..634fb40 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -94,11 +94,11 @@ TEST(LCATest, test6) { tree[1] = {0, 3}; tree[2] = {0}; - EXPECT_THROW(LCA lca(tree, 0), std::logic_error); + EXPECT_THROW(const LCA lca(tree, 0), std::logic_error); } TEST(LCATest, test7) { - vector> tree; + vector> const tree; - EXPECT_THROW(LCA lca(tree, 0), std::logic_error); + EXPECT_THROW(const LCA lca(tree, 0), std::logic_error); } \ No newline at end of file From f35c95dc2b72ff701adc26236df320da5028705f Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sun, 3 Nov 2024 21:23:09 +0000 Subject: [PATCH 14/17] fix all 4 --- task_01/src/topology_sort.cpp | 4 +++- task_02/src/algo.cpp | 4 +++- task_03/src/algo.cpp | 4 +++- task_04/src/algo.cpp | 4 +++- task_05/src/rmq.cpp | 2 ++ task_06/src/lca.cpp | 2 ++ 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/task_01/src/topology_sort.cpp b/task_01/src/topology_sort.cpp index 08d4d88..af44719 100644 --- a/task_01/src/topology_sort.cpp +++ b/task_01/src/topology_sort.cpp @@ -1 +1,3 @@ -// nothing \ No newline at end of file +// nothing + +int main() { return 0; } \ No newline at end of file diff --git a/task_02/src/algo.cpp b/task_02/src/algo.cpp index 08d4d88..af44719 100644 --- a/task_02/src/algo.cpp +++ b/task_02/src/algo.cpp @@ -1 +1,3 @@ -// nothing \ No newline at end of file +// nothing + +int main() { return 0; } \ No newline at end of file diff --git a/task_03/src/algo.cpp b/task_03/src/algo.cpp index 08d4d88..af44719 100644 --- a/task_03/src/algo.cpp +++ b/task_03/src/algo.cpp @@ -1 +1,3 @@ -// nothing \ No newline at end of file +// nothing + +int main() { return 0; } \ No newline at end of file diff --git a/task_04/src/algo.cpp b/task_04/src/algo.cpp index 08d4d88..af44719 100644 --- a/task_04/src/algo.cpp +++ b/task_04/src/algo.cpp @@ -1 +1,3 @@ -// nothing \ No newline at end of file +// nothing + +int main() { return 0; } \ No newline at end of file diff --git a/task_05/src/rmq.cpp b/task_05/src/rmq.cpp index e9b6a44..af44719 100644 --- a/task_05/src/rmq.cpp +++ b/task_05/src/rmq.cpp @@ -1 +1,3 @@ // nothing + +int main() { return 0; } \ No newline at end of file diff --git a/task_06/src/lca.cpp b/task_06/src/lca.cpp index e75c3e3..28a1844 100644 --- a/task_06/src/lca.cpp +++ b/task_06/src/lca.cpp @@ -45,3 +45,5 @@ void LCA::Dfs(const vector>& tree, int v, int p) { } } } + +int main() { return 0; } \ No newline at end of file From 8be711ffa8b33fb0d08780837b766cd9dc6e712e Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Sun, 3 Nov 2024 21:28:22 +0000 Subject: [PATCH 15/17] fix all 5 --- task_06/src/lca.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_06/src/lca.cpp b/task_06/src/lca.cpp index 28a1844..8fe7a8f 100644 --- a/task_06/src/lca.cpp +++ b/task_06/src/lca.cpp @@ -8,7 +8,7 @@ LCA::LCA(const vector>& tree, int root) { for (const auto& i : tree) if (i.empty()) throw std::logic_error("vertex vector is empty"); n = tree.size(); - const int log_n = static_cast(log2(n) + 1); + const int log_n = static_cast(log2(static_cast(n)) + 1); up.assign(n, vector(log_n, -1)); depth.resize(n); Dfs(tree, root, root); From 7fe243b27851735d909afc9eb3301a57f02f2fdb Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Thu, 9 Jan 2025 22:22:16 +0000 Subject: [PATCH 16/17] fix --- lib/src/graph.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++ lib/src/graph.hpp | 116 +++------------------------------------------- 2 files changed, 121 insertions(+), 109 deletions(-) create mode 100644 lib/src/graph.cpp diff --git a/lib/src/graph.cpp b/lib/src/graph.cpp new file mode 100644 index 0000000..85d8b98 --- /dev/null +++ b/lib/src/graph.cpp @@ -0,0 +1,114 @@ +#include "graph.hpp" +#include + +void WeightedGraph::CheckNegativeCycle(const vector& distances) { + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + throw std::logic_error("Graph contains a negative weight cycle"); + } + } + } + } + } + + bool WeightedGraph::RelaxEdges(vector& distances) { + bool updated = false; + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + distances[v] = distances[u] + table_[u][v]; + updated = true; + } + } + } + } + return updated; + } + + vector WeightedGraph::BellmanFord(size_t start) { + vector distances(vertices_number_, INF); + distances[start] = 0; + + for (size_t i = 0; i < vertices_number_ - 1; ++i) { + RelaxEdges(distances); + } + + CheckNegativeCycle(distances); + return distances; + } + + vector WeightedGraph::Dijkstra(size_t start) { + vector distances(vertices_number_, INF); + distances[start] = 0; + + std::priority_queue, vector>, std::greater<>> + pq; + pq.push({0, start}); + + while (!pq.empty()) { + const int u = pq.top().second; + const int dist_u = pq.top().first; + pq.pop(); + + if (dist_u > distances[u]) continue; + + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + const int new_dist = distances[u] + table_[u][v]; + if (new_dist < distances[v]) { + distances[v] = new_dist; + pq.push({new_dist, v}); + } + } + } + } + return distances; + } + + vector> WeightedGraph::Johnson() { + vector h(vertices_number_ + 1, 0); + + table_.push_back(vector(vertices_number_, 0)); + try { + h = BellmanFord(vertices_number_); + } catch (const std::logic_error&) { + throw std::logic_error( + "Graph contains a negative weight cycle, Johnson's algorithm cannot " + "be applied"); + } + table_.pop_back(); + + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF) { + table_[u][v] += h[u] - h[v]; + } + } + } + + vector> distances(vertices_number_); + for (size_t u = 0; u < vertices_number_; ++u) { + distances[u] = Dijkstra(u); + for (size_t v = 0; v < vertices_number_; ++v) { + if (distances[u][v] != INF) { + distances[u][v] += h[v] - h[u]; + } + } + } + + return distances; + } + + WeightedGraph::WeightedGraph(vector>&& table) + : table_(std::move(table)), vertices_number_(table_.size()) { + if (table_.empty()) + throw std::logic_error( + "the graph was not created because the input table is empty"); + for (size_t i = 0; i < table_.size(); i++) + if (table_[i].size() != table_.size()) + throw std::logic_error( + "the graph was not created because the input table is incorrect"); + } \ No newline at end of file diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index b4ca737..96ecff1 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include @@ -22,7 +20,7 @@ class Graph { public: Graph(size_t number) { - if (number <= 0) throw std::logic_error("number must be positive!"); + if (number == 0) throw std::logic_error("number must be positive!"); vertices_number_ = number; adjacency_list_.resize(vertices_number_ + 1); } @@ -64,118 +62,18 @@ class WeightedGraph { vector> table_; size_t vertices_number_; - void CheckNegativeCycle(const vector& distances) { - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - if (distances[u] + table_[u][v] < distances[v]) { - throw std::logic_error("Graph contains a negative weight cycle"); - } - } - } - } - } + void CheckNegativeCycle(const vector& distances); - bool RelaxEdges(vector& distances) { - bool updated = false; - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - if (distances[u] + table_[u][v] < distances[v]) { - distances[v] = distances[u] + table_[u][v]; - updated = true; - } - } - } - } - return updated; - } - - vector BellmanFord(size_t start) { - vector distances(vertices_number_, INF); - distances[start] = 0; + bool RelaxEdges(vector& distances); - for (size_t i = 0; i < vertices_number_ - 1; ++i) { - RelaxEdges(distances); - } - - CheckNegativeCycle(distances); - return distances; - } + vector BellmanFord(size_t start); public: - WeightedGraph(vector>&& table) - : table_(std::move(table)), vertices_number_(table_.size()) { - if (table_.empty()) - throw std::logic_error( - "the graph was not created because the input table is empty"); - for (size_t i = 0; i < table_.size(); i++) - if (table_[i].size() != table_.size()) - throw std::logic_error( - "the graph was not created because the input table is incorrect"); - } - - vector Dijkstra(size_t start) { - vector distances(vertices_number_, INF); - distances[start] = 0; - - std::priority_queue, vector>, std::greater<>> - pq; - pq.push({0, start}); - - while (!pq.empty()) { - const int u = pq.top().second; - const int dist_u = pq.top().first; - pq.pop(); + WeightedGraph(vector>&& table); - if (dist_u > distances[u]) continue; + vector Dijkstra(size_t start); - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - const int new_dist = distances[u] + table_[u][v]; - if (new_dist < distances[v]) { - distances[v] = new_dist; - pq.push({new_dist, v}); - } - } - } - } - return distances; - } - - vector> Johnson() { - vector h(vertices_number_ + 1, 0); - - table_.push_back(vector(vertices_number_, 0)); - try { - h = BellmanFord(vertices_number_); - } catch (const std::logic_error&) { - throw std::logic_error( - "Graph contains a negative weight cycle, Johnson's algorithm cannot " - "be applied"); - } - table_.pop_back(); - - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF) { - table_[u][v] += h[u] - h[v]; - } - } - } - - vector> distances(vertices_number_); - for (size_t u = 0; u < vertices_number_; ++u) { - distances[u] = Dijkstra(u); - for (size_t v = 0; v < vertices_number_; ++v) { - if (distances[u][v] != INF) { - distances[u][v] += h[v] - h[u]; - } - } - } - - return distances; - } + vector> Johnson(); }; template From 8e94d0e4cef7f351007bd13af03754351f2ec354 Mon Sep 17 00:00:00 2001 From: Sukhanov George Date: Thu, 9 Jan 2025 22:24:34 +0000 Subject: [PATCH 17/17] fix format --- lib/src/graph.cpp | 163 +++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/lib/src/graph.cpp b/lib/src/graph.cpp index 85d8b98..64729ab 100644 --- a/lib/src/graph.cpp +++ b/lib/src/graph.cpp @@ -1,114 +1,115 @@ #include "graph.hpp" + #include void WeightedGraph::CheckNegativeCycle(const vector& distances) { - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - if (distances[u] + table_[u][v] < distances[v]) { - throw std::logic_error("Graph contains a negative weight cycle"); - } + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + throw std::logic_error("Graph contains a negative weight cycle"); } } } } - - bool WeightedGraph::RelaxEdges(vector& distances) { - bool updated = false; - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - if (distances[u] + table_[u][v] < distances[v]) { - distances[v] = distances[u] + table_[u][v]; - updated = true; - } +} + +bool WeightedGraph::RelaxEdges(vector& distances) { + bool updated = false; + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + if (distances[u] + table_[u][v] < distances[v]) { + distances[v] = distances[u] + table_[u][v]; + updated = true; } } } - return updated; } + return updated; +} - vector WeightedGraph::BellmanFord(size_t start) { - vector distances(vertices_number_, INF); - distances[start] = 0; - - for (size_t i = 0; i < vertices_number_ - 1; ++i) { - RelaxEdges(distances); - } +vector WeightedGraph::BellmanFord(size_t start) { + vector distances(vertices_number_, INF); + distances[start] = 0; - CheckNegativeCycle(distances); - return distances; + for (size_t i = 0; i < vertices_number_ - 1; ++i) { + RelaxEdges(distances); } - vector WeightedGraph::Dijkstra(size_t start) { - vector distances(vertices_number_, INF); - distances[start] = 0; + CheckNegativeCycle(distances); + return distances; +} - std::priority_queue, vector>, std::greater<>> - pq; - pq.push({0, start}); +vector WeightedGraph::Dijkstra(size_t start) { + vector distances(vertices_number_, INF); + distances[start] = 0; - while (!pq.empty()) { - const int u = pq.top().second; - const int dist_u = pq.top().first; - pq.pop(); + std::priority_queue, vector>, std::greater<>> + pq; + pq.push({0, start}); - if (dist_u > distances[u]) continue; + while (!pq.empty()) { + const int u = pq.top().second; + const int dist_u = pq.top().first; + pq.pop(); - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF && distances[u] != INF) { - const int new_dist = distances[u] + table_[u][v]; - if (new_dist < distances[v]) { - distances[v] = new_dist; - pq.push({new_dist, v}); - } + if (dist_u > distances[u]) continue; + + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF && distances[u] != INF) { + const int new_dist = distances[u] + table_[u][v]; + if (new_dist < distances[v]) { + distances[v] = new_dist; + pq.push({new_dist, v}); } } } - return distances; } + return distances; +} + +vector> WeightedGraph::Johnson() { + vector h(vertices_number_ + 1, 0); + + table_.push_back(vector(vertices_number_, 0)); + try { + h = BellmanFord(vertices_number_); + } catch (const std::logic_error&) { + throw std::logic_error( + "Graph contains a negative weight cycle, Johnson's algorithm cannot " + "be applied"); + } + table_.pop_back(); - vector> WeightedGraph::Johnson() { - vector h(vertices_number_ + 1, 0); - - table_.push_back(vector(vertices_number_, 0)); - try { - h = BellmanFord(vertices_number_); - } catch (const std::logic_error&) { - throw std::logic_error( - "Graph contains a negative weight cycle, Johnson's algorithm cannot " - "be applied"); - } - table_.pop_back(); - - for (size_t u = 0; u < vertices_number_; ++u) { - for (size_t v = 0; v < vertices_number_; ++v) { - if (table_[u][v] != INF) { - table_[u][v] += h[u] - h[v]; - } + for (size_t u = 0; u < vertices_number_; ++u) { + for (size_t v = 0; v < vertices_number_; ++v) { + if (table_[u][v] != INF) { + table_[u][v] += h[u] - h[v]; } } + } - vector> distances(vertices_number_); - for (size_t u = 0; u < vertices_number_; ++u) { - distances[u] = Dijkstra(u); - for (size_t v = 0; v < vertices_number_; ++v) { - if (distances[u][v] != INF) { - distances[u][v] += h[v] - h[u]; - } + vector> distances(vertices_number_); + for (size_t u = 0; u < vertices_number_; ++u) { + distances[u] = Dijkstra(u); + for (size_t v = 0; v < vertices_number_; ++v) { + if (distances[u][v] != INF) { + distances[u][v] += h[v] - h[u]; } } - - return distances; } - WeightedGraph::WeightedGraph(vector>&& table) - : table_(std::move(table)), vertices_number_(table_.size()) { - if (table_.empty()) + return distances; +} + +WeightedGraph::WeightedGraph(vector>&& table) + : table_(std::move(table)), vertices_number_(table_.size()) { + if (table_.empty()) + throw std::logic_error( + "the graph was not created because the input table is empty"); + for (size_t i = 0; i < table_.size(); i++) + if (table_[i].size() != table_.size()) throw std::logic_error( - "the graph was not created because the input table is empty"); - for (size_t i = 0; i < table_.size(); i++) - if (table_[i].size() != table_.size()) - throw std::logic_error( - "the graph was not created because the input table is incorrect"); - } \ No newline at end of file + "the graph was not created because the input table is incorrect"); +} \ No newline at end of file