diff --git a/Ford_Bellman.cpp b/Ford_Bellman.cpp index 259151d..4ba911d 100644 --- a/Ford_Bellman.cpp +++ b/Ford_Bellman.cpp @@ -1,17 +1,15 @@ #define int long long -struct Edge{ - int u, v; - int weight; - friend istream &operator >> (istream &is, Edge &e){ +struct Edge { + int u, v, weight; + friend istream &operator >> (istream &is, Edge &e) { is >> e.u >> e.v >> e.weight; --e.u, --e.v; return is; } - }; -void Ford_Bellman() { +void Ford_Bellman(void) { int n, m; cin >> n >> m; vector dist(n, -1e18); @@ -19,26 +17,22 @@ void Ford_Bellman() { vector edges(m); cin >> edges; dist[0] = 0; - for (int i = 0; i < n - 1; ++i) { - for (auto e : edges) { + for (int i = 0; i < n - 1; ++i) + for (auto e : edges) if (dist[e.v] < dist[e.u] + e.weight) { dist[e.v] = dist[e.u] + e.weight; prev[e.v]= e.u; } - } - } - //if we have not got negative cycles then all evaluated + + /// if we have not got negative cycles then all evaluated Vertex *end = nullptr; - for (auto e : edges) { - if (e.second->dist > e.first->dist + weight[e.first, e.second]) { + for (auto e : edges) + if (e.second->dist > e.first->dist + weight[e.first, e.second]) end = e.second; - } - } - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) end = end->pred; - } Vertex *p = end; - while (p != end){ + while (p != end) { cout << p; p = p->pred; } diff --git a/adjacencyclass.cpp b/adjacencyclass.cpp index 4db0c8f..9fc6658 100644 --- a/adjacencyclass.cpp +++ b/adjacencyclass.cpp @@ -1,60 +1,206 @@ -#define WHITE 0 -#define GRAY 1 -#define BLACK 2 using namespace std; -constexpr size_t MAIN_SIZE = 64; - -struct basic_vertex { - int x; - int used; - vector neibh; - basic_vertex(int a) : x(a), used(WHITE) - { neibh.reserve(MAIN_SIZE); } -}; - -class Vertex : public basic_vertex { - Vertex(int a) : basic_vertex(a) - {} - vector weight; - Vertex *parent; -}; - -void bind(basic_vertex *a, basic_vertex *b) { - a->neibh.push_back(b); - b->neibh.push_back(a); -} -void dfs(basic_vertex *v) { - v->used = BLACK; - for (Vertex * &u : v->neibh) - if (u->used = WHITE) - dfs(u); -} +namespace graphs { + struct graph { + struct vertex { + struct edge { + vertex *p; + int weight; -void bind_or(basic_vertex *a, basic_vertex *b) { - a->neibh.push_back(b); -} + edge(vertex *p, int w) : p(p), weight(w) {} -void remove(basic_vertex *a, basic_vertex *b) { - auto i1 = find(a->neibh.begin(), a->neibh.end(), b); - auto i2 = find(b->neibh.begin(), b->neibh.end(), a); - a->neibh.erase(i1); - b->neibh.erase(i2); -} + bool operator<(const edge &e) const { return *p < *e.p; } + }; -void remove_or(basic_vertex *a, basic_vertex *b) { - a->neibh.erase(find(a->neibh.begin(), a->neibh.end(), b)); -} + vector edges; + int n, component, up, depth, degree; + int x, y; + bool visited = false; + bool artpoint; + + bool operator<(const vertex &v) const { return n < v.n; } + + bool operator==(const vertex &v) const { return n == v.n; } + + explicit vertex(int n = 0) : component(-1), n(n), depth(1e15), up(-1), degree(0) {} + + void dfs() { + for (edge &e : edges) { + e.p->dfs(); + } + } + + void relax() { + for (edge e : edges) { + if (e.p->depth > depth + e.weight) e.p->depth = depth + e.weight; + } + } + + void set_comp(int c) { + if (component != -1) return; else component = c; + for (edge &e : edges) e.p->set_comp(c); + } + + void bfs() { + up = depth = 0; + queue queue; + queue.push(this); + while (!queue.empty()) { + vertex *v = queue.front(); + queue.pop(); + for (edge e : v->edges) { + if (e.p->depth != -1) continue; + queue.push(e.p); + e.p->up = e.p->depth = v->depth + 1; + } + } + } + + void top_sort(vector &top_sorted) { + visited = true; + for (edge e : edges) { + if (!e.p->visited) e.p->top_sort(top_sorted); + } + top_sorted.push_back(this); + } + + bool find(vertex *f, vector way) { + if (*this == *f) return true; + visited = true; + for (edge e : edges) { + if (!e.p->visited) { + if (e.p->find(f, way)) { + way.push_back(this); + return true; + } + } + } + return false; + } + + void find_artpoints(vertex *parent) { + visited = true; + int count = 0; + for (edge e : edges) { + if (!e.p->visited) { + e.p->up = e.p->depth = depth + 1; + e.p->find_artpoints(this); + count++; + up = min(up, e.p->up); + degree = max(degree, e.p->up); + } + if (e.p != parent) + up = min(up, e.p->depth); + } + if ((parent != nullptr && degree >= depth && count > 0) || (parent == nullptr && count > 1)) + this->artpoint = true; + } + + friend ostream &operator<<(ostream &os, vertex *v) { + os << v->n + 1; + return os; + } + }; + + vector vertices; + int vertex_count, edge_count; + bool directed, weight; + + explicit graph(int n, int m, bool directed = false, bool weight = false) + : vertices(n), vertex_count(n), edge_count(m), directed(directed), weight(weight) { + for (int i = 0; i < n; ++i) { + vertices[i] = new vertex(i); + } + } + + inline vertex *operator[](int idx) { return vertices[idx]; } + + void link(int i, int j, int w = 1) { + vertices[i]->edges.emplace_back(vertices[j], w); + if (!directed) vertices[j]->edges.emplace_back(vertices[i], w); + } + + void create(int R, int x) { + for (vertex *v : vertices) v->edges.clear(); + for (int i = 0; i < vertex_count; ++i) { + for (int j = i + 1; j < vertex_count; ++j) { + if (i == x || j == x) continue; + if (((vertices[i]->x - vertices[j]->x) * (vertices[i]->x - vertices[j]->x) + + (vertices[i]->y - vertices[j]->y) * (vertices[i]->y - vertices[j]->y)) <= R) + link(i, j); + } + } + } + + friend istream &operator>>(istream &is, graph &G) { + for (int i = 0; i < G.edge_count; ++i) { + int u = 0, v = 0, w = 1; + cin >> u >> v; + if (G.weight) cin >> w; + G.link(u - 1, v - 1, w); + } + return is; + } + + vector find_artpoints() { + for (vertex *v : vertices) v->visited = false; + for (vertex *v : vertices) { + if (!v->visited) { + v->up = v->depth = 0; + v->find_artpoints(nullptr); + } + } + vector artpoints = *new vector; + for (vertex *v : vertices) { + if (v->artpoint) artpoints.push_back(v); + } + return artpoints; + } + + vector top_sort() { + for (vertex *v : vertices) v->visited = false; + vector top_sorted = *new vector; + for (vertex *v : vertices) { + if (!v->visited) { + v->top_sort(top_sorted); + } + } + reverse(top_sorted.begin(), top_sorted.end()); + return top_sorted; + } + + vector way(int s, int t) { + for (vertex *v : vertices) v->visited = false; + vector ans; + vertices[s]->find(vertices[t], ans); + return ans; + } + + int comp_count() { + for (vertex *v : vertices) v->component = -1; + int c = 0; + for (vertex *v : vertices) { + if (v->component == -1) v->set_comp(c++); + } + return c; + } + }; + + struct tree : graph { + vertex *root; + + explicit tree(int n, int root = 0, bool weight = false) + : graph(n, n - 1, true, weight), root(vertices[0]) {} + + friend istream &operator>>(istream &is, tree &T) { + for (int i = 0; i < T.edge_count; ++i) { + int parent = 0, weight = 0; + cin >> parent; + if (weight) cin >> weight; + T[parent]->edges.emplace_back(T[i + 1], weight); + } + return is; + } + }; -bool has_cycle(basic_vertex *v) -{ - v->used = GRAY; - for (auto &u : v->neibh) { - if (u->used == WHITE) { - if (dfs(u)) return true; - } else if (u->used == GRAY) - return true; - } - v->used = BLACK; - return false; } diff --git a/adjacencymatrix.cpp b/adjacencymatrix.cpp index 08443c2..19960c4 100644 --- a/adjacencymatrix.cpp +++ b/adjacencymatrix.cpp @@ -8,6 +8,8 @@ class AdjMatrix { int **g; int n; AgjMatrix(int _n) { + if (_n > 20000) // very rarely you have more than 512MB + throw exception("'_n' is too large for matrix creating!"); n = _n; g = new int*[n]; for (int i = 0; i < n; i++) @@ -18,7 +20,7 @@ class AdjMatrix { delete[] g[i]; delete[] g; } - + void floyd() /** * if you want to save original weights, you should copy the graph @@ -41,3 +43,37 @@ void floyd(int **g, int n) for (int j = 0; j < n; j++) g[i][j] = min(g[i][j], g[i][k] + g[k][j]); } + +void floyd_with_path(int **g, int n) { + int **next = new int*[n]; + for (int i = 0; i < n; i++) + next[i] = new int[n]; + for (int k = 0; k < n; k++) i + for (int i = 0; i < n; i++) u + for (int j = 0; j < n; j++) v + if (g[i][k] + g[k][j] < g[i][j]) { + g[i][j] = g[i][k] + g[k][j]; + next[i][j] = next[i][k]; + } + return next; +} + +void readAdjMatOr(AdjMatrix &g) { + int n; + cin >> n; + g = AgjMatrix(n); + for (int i = 0, a, b, w; i < n; i++) { + cin >> a >> b >> w; + g.g[a][b] = w; + } +} + +void readAdjMatNOr(AdjMatrix &g) { + int n; + cin >> n; + g = AgjMatrix(n); + for (int i = 0, a, b, w; i < n; i++) { + cin >> a >> b >> w; + g.g[a][b] = g.g[b][a] = w; + } +} diff --git a/djikstra.cpp b/djikstra.cpp new file mode 100644 index 0000000..c113704 --- /dev/null +++ b/djikstra.cpp @@ -0,0 +1,88 @@ +typedef vector>> graph; +constexpr int INF = INT_MAX; + +vector djkstra(graph &g, int s, vector &prev) +/** Complexity: O(n ^ 2 + m) + */ +{ + int n = g.size(); + vector d(n, INF); + vector used(n, false); + d[s] = 0; + for (int i = 0; i < n; i++) { + int v = -1; + for (int j = 0; j < n; j++) + if (!used[j] && (v == -1 || d[j] < d[v])) + v = j; + if (d[v] == INF) + break; + used[v] = true; + + for (int j = 0; j < g[v].size(); j++) { + int to = g[v][j].first; + int wg = g[v][j].second; + if (d[v] + wg < d[to]) { + d[to] = d[v] + wg; + prev[to] = v; + } + } + } + return d; +} + + +vector djkstra_fast(vector>> &g, int s, vector &prev) +/** Complexity: O(n log(n) + m log(n)) + */ +{ + int n = g.size(); + vector d(n, INF); + d[s] = 0; + set> unused; + for (int i = 0; i < n; i++) + unused.insert({d[i], i}); // (val, index) + for (int i = 0; i < n; i++) { + int v = unused.begin()->second; // index of v + unused.erase(unused.begin()); + for (pair &u : g[v]) { + int to = u.first, wg = u.second; + if (d[v] + wg < d[to]) { + if (unused.find({d[to], to}) != unused.end()) { + unused.erase(unused.find({d[to], to})); + } + d[to] = d[v] + wg; + prev[to] = v; + unused.insert({d[to], to}); + } + } + } + return d; +} + + +/** + n - vertex count + m - edges count + + What algorithm should you use? + basic: O(n ^ 2 + m) + fast: O(n log(n) + m log(n)) + + So, m <= n(n - 1) if there are not multiple edges + (if they are, you should just choose an edge with min weight between each pair of vertexes) + + So, we get an equation: + n ^ 2 + m = n log(n) + m log(n) + + The solution is: + m = n(n - log(n)) / (log(n) - 1) + + So, we have 2 cases: + * m < n(n - log(n)) / (log(n) - 1) ==> + fast algorithm is optimal + * m > n(n - log(n)) / (log(n) - 1) ==> + basic algorithm is optimal (for example imagine m ~ n ^ 2, then: first (basic) + algorithm is O(n ^ 2) and second (fast) is O(log(n) n ^ 2) + +*/ + diff --git a/ford_bellman_clear.cpp b/ford_bellman_clear.cpp new file mode 100644 index 0000000..2b385ad --- /dev/null +++ b/ford_bellman_clear.cpp @@ -0,0 +1,69 @@ +struct edge { + int u, v, w; +}; + +/// if there are negative cycles, +/// that mean that there is no shorteset path ( +/// we can repeat going on negative edges as long +/// as we want and get more and more shorter path + +bool fordBellman(vector &d, int start, const vector &edges) +/** + * d - distanse array (s -> v) + * edges - all edges in graph + * returns existing neg cycles in a graph + */ +{ + int n = d.size(); + for (int i = 0; i < n; i++) + d[v] = 1; + d[start] = 0; + + for (int i = 0; i < n; i++) + for (const edge &E : edges) // E = (u, v) + if (d[E.v] > d[E.u] + E.w) + d[E.v] = d[E.u] + E.w; + + for (edge E : edges) + if (d[E.v] > d[E.u] + E.w) /// better solution exists if only there is a negative cycle + return false; + return true; +} + + +vector fordBellmanNCyc(vector &d, int start, const vector &edges) +/** + * d - distanse array (s -> v) + * edges - all edges in graph + * returns a neg cycle in a graph + */ +{ + vector ans; + vector p(n, -1); + int n = d.size(); + for (int i = 0; i < n; i++) + d[v] = 1; + d[start] = 0; + + for (int i = 0; i < n; i++) + for (const edge &E : edges) // E = (u, v) + if (d[E.v] > d[E.u] + E.w) { + d[E.v] = d[E.u] + E.w; + p[v] = u; + } + + for (const edge &E : edges) + if (d[E.v] > d[E.u] + E.w) { + int u, v; + for (int i = 0; i < n; i++) + v = p[v]; + u = v; + while (u != p[v]) { + ans.push_back(v); + v = p[v]; + } + break; + } + return ans; +} + diff --git a/lightadjclass.cpp b/lightadjclass.cpp new file mode 100644 index 0000000..4db0c8f --- /dev/null +++ b/lightadjclass.cpp @@ -0,0 +1,60 @@ +#define WHITE 0 +#define GRAY 1 +#define BLACK 2 +using namespace std; +constexpr size_t MAIN_SIZE = 64; + +struct basic_vertex { + int x; + int used; + vector neibh; + basic_vertex(int a) : x(a), used(WHITE) + { neibh.reserve(MAIN_SIZE); } +}; + +class Vertex : public basic_vertex { + Vertex(int a) : basic_vertex(a) + {} + vector weight; + Vertex *parent; +}; + +void bind(basic_vertex *a, basic_vertex *b) { + a->neibh.push_back(b); + b->neibh.push_back(a); +} + +void dfs(basic_vertex *v) { + v->used = BLACK; + for (Vertex * &u : v->neibh) + if (u->used = WHITE) + dfs(u); +} + +void bind_or(basic_vertex *a, basic_vertex *b) { + a->neibh.push_back(b); +} + +void remove(basic_vertex *a, basic_vertex *b) { + auto i1 = find(a->neibh.begin(), a->neibh.end(), b); + auto i2 = find(b->neibh.begin(), b->neibh.end(), a); + a->neibh.erase(i1); + b->neibh.erase(i2); +} + +void remove_or(basic_vertex *a, basic_vertex *b) { + a->neibh.erase(find(a->neibh.begin(), a->neibh.end(), b)); +} + +bool has_cycle(basic_vertex *v) +{ + v->used = GRAY; + for (auto &u : v->neibh) { + if (u->used == WHITE) { + if (dfs(u)) return true; + } else if (u->used == GRAY) + return true; + } + v->used = BLACK; + return false; +} diff --git a/main_interfaces.hpp b/main_interfaces.hpp deleted file mode 100644 index 8b13789..0000000 --- a/main_interfaces.hpp +++ /dev/null @@ -1 +0,0 @@ - diff --git a/recommended-non-weiht.hpp b/recommended-non-weiht.hpp index 6ae3988..69c1a45 100644 --- a/recommended-non-weiht.hpp +++ b/recommended-non-weiht.hpp @@ -49,7 +49,6 @@ struct Graph { void bfs(int); void find_bridges(int); void points_con(int); - void djiksta(int, int); void condense(int); bool hascycle(); int shortestcycle(); @@ -109,3 +108,24 @@ void Graph::find_bridges(int v, int pr = -1) { ans.push_back({v, pr}); } } +/** TODO: move following function to the class */ +vector ans; +void ts_dfs(int v) { + used[v] = GRAY; + for (auto u : g[v]) { + if (used[u] == 1) + throw std::exception("Graph with cycles!"); + if (used[u] == 0) + ts_dfs(u); + } + used[v] = BLACK; + ans.push_back(v); +} + +void topsort() { + for (int i = 0; i < n; i++) + if (!used[i]) + ts_dfs(i); + for (int i = 0; i < ans.size() / 2; i++) + swap(ans[i], ans[ans.size() - i - 1]); +}