Skip to content

solutions #4

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
115 changes: 115 additions & 0 deletions lib/src/graph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "graph.hpp"

#include <queue>

void WeightedGraph::CheckNegativeCycle(const vector<int>& 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<int>& 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<int> WeightedGraph::BellmanFord(size_t start) {
vector<int> distances(vertices_number_, INF);
distances[start] = 0;

for (size_t i = 0; i < vertices_number_ - 1; ++i) {
RelaxEdges(distances);
}

CheckNegativeCycle(distances);
return distances;
}

vector<int> WeightedGraph::Dijkstra(size_t start) {
vector<int> distances(vertices_number_, INF);
distances[start] = 0;

std::priority_queue<pair<int, int>, vector<pair<int, int>>, 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<vector<int>> WeightedGraph::Johnson() {
vector<int> h(vertices_number_ + 1, 0);

table_.push_back(vector<int>(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<vector<int>> 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<vector<int>>&& 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");
}
150 changes: 150 additions & 0 deletions lib/src/graph.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#pragma once

#include <cmath>
#include <limits>
#include <list>
#include <stdexcept>
#include <vector>

using std::list;
using std::pair;
using std::vector;

const int INF = std::numeric_limits<int>::max();

template <typename T>
class Graph {
private:
size_t vertices_number_;
vector<vector<T>> adjacency_list_;

public:
Graph(size_t number) {
if (number == 0) throw std::logic_error("number must be positive!");
vertices_number_ = number;
adjacency_list_.resize(vertices_number_ + 1);
}

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);
}

void TopologySortStep(int current_vertice, vector<bool>& visited_vertices,
list<T>& list) {
visited_vertices[current_vertice] = true;
for (const auto& neighbor : adjacency_list_[current_vertice]) {
if (!visited_vertices[neighbor]) {
TopologySortStep(neighbor, visited_vertices, list);
}
}
list.push_front(current_vertice);
}

list<T> TopologySort() {
list<T> list;
vector<bool> 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 WeightedGraph {
private:
vector<vector<int>> table_;
size_t vertices_number_;

void CheckNegativeCycle(const vector<int>& distances);

bool RelaxEdges(vector<int>& distances);

vector<int> BellmanFord(size_t start);

public:
WeightedGraph(vector<vector<int>>&& table);

vector<int> Dijkstra(size_t start);

vector<vector<int>> Johnson();
};

template <typename T>
class BridgeGraph {
private:
size_t vertices_number_;
list<T>* adjacency_list_;
vector<int> tin_, low_;
vector<bool> visited_;
vector<pair<int, int>> bridges_;
vector<int> 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 (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);
}

public:
BridgeGraph(size_t number) {
if (number <= 0) throw std::logic_error("number must be positive!");
vertices_number_ = number;
adjacency_list_ = new list<T>[vertices_number_ + 1];
}

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);
}

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 (size_t i = 0; i <= vertices_number_; ++i) {
if (!visited_[i]) dfs(i, -1, timer);
}
}

vector<pair<int, int>> GiveBridges() { return bridges_; }
vector<int> GivePoints() { return articulation_points_; }
};
2 changes: 1 addition & 1 deletion lib/src/util.cpp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#include "util.hpp"
#include "util.hpp"
1 change: 0 additions & 1 deletion task_01/src/main.cpp

This file was deleted.

45 changes: 43 additions & 2 deletions task_01/src/test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
#include <gtest/gtest.h>

TEST(Test, Simple) {
ASSERT_EQ(1, 1); // Stack []
#include <graph.hpp>

TEST(TopologySort, test1) {
Graph<int> g(6);
EXPECT_THROW(g.AddEdge(5, 5), std::logic_error);
}

TEST(TopologySort, test2) {
EXPECT_THROW(Graph<int> g(-5), std::logic_error);
EXPECT_THROW(Graph<int> g(0), std::logic_error);
}

TEST(TopologySort, test3) {
Graph<int> g(2);
EXPECT_THROW(g.AddEdge(5, 6), std::logic_error);
}

TEST(TopologySort, test4) {
Graph<int> g(5);
g.AddEdge(5, 2);
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<int>({4, 5, 2, 3, 1}));
}

TEST(TopologySort, test5) {
Graph<int> 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<int>({12, 11, 10, 9, 1, 2, 3, 4, 5, 6, 7, 8}));
}
3 changes: 3 additions & 0 deletions task_01/src/topology_sort.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// nothing

int main() { return 0; }
3 changes: 3 additions & 0 deletions task_02/src/algo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// nothing

int main() { return 0; }
3 changes: 0 additions & 3 deletions task_02/src/main.cpp

This file was deleted.

21 changes: 0 additions & 21 deletions task_02/src/stack.cpp

This file was deleted.

23 changes: 0 additions & 23 deletions task_02/src/stack.hpp

This file was deleted.

Loading
Loading