This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "tools/naive_dijkstra.hpp"
It solves the single source shortest path problem on a given graph which is not necessarily simple. All the edges must have non-nagative costs.
naive_dijkstra<Directed, T> graph(int n);
If the type parameter <Directed>
is true
, it creates a directed graph with $n$ vertices and $0$ edges.
If the type parameter <Directed>
is false
, it creates an undirected graph with $n$ vertices and $0$ edges.
The type parameter <T>
represents the type of the cost.
int graph.size();
It returns $n$.
int graph.add_edge(int u, int v, T w);
If <Directed>
is true
, it adds a directed edge oriented from $u$ to $v$ with cost w
.
If <Directed>
is false
, it adds an undirected edge between $u$ and $v$ with cost w
.
It returns an integer $k$ such that this is the $k$-th ($0$ indexed) edge that is added.
struct edge {
int from;
int to;
T cost;
};
edge graph.get_edge(int k);
It returns the $k$-th ($0$ indexed) edge.
std::vector<edge> graph.edges();
It returns all the edges in the graph.
The edges are ordered in the same order as added by add_edge
.
(1) std::vector<T> graph.query(int s);
(2) std::vector<T> graph.query<false>(int s);
(3) tools::shortest_path_tree<T, (anonymous type)> graph.query<true>(int s);
graph.query<true>(s).dist()
.#ifndef TOOLS_NAIVE_DIJKSTRA_HPP
#define TOOLS_NAIVE_DIJKSTRA_HPP
#include <algorithm>
#include <cassert>
#include <iterator>
#include <limits>
#include <numeric>
#include <tuple>
#include <utility>
#include <vector>
#include "tools/chmin.hpp"
#include "tools/less_by.hpp"
#include "tools/shortest_path_tree.hpp"
namespace tools {
template <bool Directed, typename T>
class naive_dijkstra {
public:
struct edge {
int from;
int to;
T cost;
};
private:
int m_size;
::std::vector<edge> m_edges;
::std::vector<int> m_graph;
public:
naive_dijkstra() = default;
explicit naive_dijkstra(const int n) : m_size(n), m_graph(n * n, -1) {
}
int size() const {
return this->m_size;
}
int add_edge(int u, int v, const T w) {
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
assert(w >= 0);
if constexpr (!Directed) {
::std::tie(u, v) = ::std::minmax({u, v});
}
this->m_edges.push_back({u, v, w});
if (this->m_graph[u * this->size() + v] < 0 || w < this->m_edges[this->m_graph[u * this->size() + v]].cost) {
this->m_graph[u * this->size() + v] = this->m_edges.size() - 1;
if constexpr (!Directed) {
this->m_graph[v * this->size() + u] = this->m_edges.size() - 1;
}
}
return this->m_edges.size() - 1;
}
const edge& get_edge(const int k) const & {
assert(0 <= k && k < ::std::ssize(this->m_edges));
return this->m_edges[k];
}
edge get_edge(const int k) && {
assert(0 <= k && k < ::std::ssize(this->m_edges));
return ::std::move(this->m_edges[k]);
}
const ::std::vector<edge>& edges() const & {
return this->m_edges;
}
::std::vector<edge> edges() && {
return ::std::move(this->m_edges);
}
template <bool Restore = false>
auto query(const int s) const {
assert(0 <= s && s < this->size());
::std::vector<T> dist(this->size(), ::std::numeric_limits<T>::max());
dist[s] = 0;
::std::vector<int> prev(Restore ? this->size() : 0, -1);
::std::vector<int> Q(this->size());
::std::iota(Q.begin(), Q.end(), 0);
while (!Q.empty()) {
const auto min_it = ::std::ranges::min_element(Q, ::tools::less_by([&](const auto v) { return dist[v]; }));
const auto here = *min_it;
if (dist[here] == ::std::numeric_limits<T>::max()) break;
::std::iter_swap(min_it, ::std::prev(Q.end()));
Q.pop_back();
for (const auto next : Q) {
const auto edge_id = this->m_graph[here * this->size() + next];
if (edge_id >= 0 && ::tools::chmin(dist[next], dist[here] + this->m_edges[edge_id].cost)) {
if constexpr (Restore) {
prev[next] = edge_id;
}
}
}
}
if constexpr (Restore) {
return ::tools::shortest_path_tree(dist, prev, [&](const auto e, const auto v) {
return this->m_edges[e].from ^ (Directed ? 0 : this->m_edges[e].to ^ v);
});
} else {
return dist;
}
}
};
}
#endif
#line 1 "tools/naive_dijkstra.hpp"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <limits>
#include <numeric>
#include <tuple>
#include <utility>
#include <vector>
#line 1 "tools/chmin.hpp"
#include <type_traits>
#line 6 "tools/chmin.hpp"
namespace tools {
template <typename M, typename N>
bool chmin(M& lhs, const N& rhs) {
bool updated;
if constexpr (::std::is_integral_v<M> && ::std::is_integral_v<N>) {
updated = ::std::cmp_less(rhs, lhs);
} else {
updated = rhs < lhs;
}
if (updated) lhs = rhs;
return updated;
}
}
#line 1 "tools/less_by.hpp"
namespace tools {
template <class F>
class less_by {
private:
F selector;
public:
less_by(const F& selector) : selector(selector) {
}
template <class T>
bool operator()(const T& x, const T& y) const {
return selector(x) < selector(y);
}
};
}
#line 1 "tools/shortest_path_tree.hpp"
#line 7 "tools/shortest_path_tree.hpp"
#include <ranges>
#line 10 "tools/shortest_path_tree.hpp"
namespace tools {
template <typename Cost, typename F>
class shortest_path_tree {
::std::vector<Cost> m_dist;
::std::vector<int> m_from;
F m_get_vertex;
public:
shortest_path_tree() = default;
template <::std::ranges::range R1, ::std::ranges::range R2>
shortest_path_tree(R1&& d, R2&& p, const F& f) : m_get_vertex(f) {
::std::ranges::copy(d, ::std::back_inserter(this->m_dist));
::std::ranges::copy(p, ::std::back_inserter(this->m_from));
assert(this->m_dist.size() == this->m_from.size());
assert(::std::ranges::all_of(this->m_from, [](const auto p_i) { return p_i >= -1; }));
}
int size() const {
return this->m_dist.size();
}
const ::std::vector<Cost>& dist() const & {
return this->m_dist;
}
::std::vector<Cost> dist() && {
return ::std::move(this->m_dist);
}
Cost dist(const int v) const {
assert(0 <= v && v < this->size());
return this->m_dist[v];
}
int from_vertex(const int v) const {
assert(0 <= v && v < this->size());
return this->m_from[v] >= 0 ? this->m_get_vertex(this->m_from[v], v) : -1;
}
int from_edge_id(const int v) const {
assert(0 <= v && v < this->size());
return this->m_from[v];
}
::std::vector<int> vertex_path(const int v) const {
assert(0 <= v && v < this->size());
::std::vector<int> path;
for (int u = v; u >= 0; u = this->from_vertex(u)) {
path.push_back(u);
}
::std::ranges::reverse(path);
return path;
}
::std::vector<int> edge_id_path(const int v) const {
assert(0 <= v && v < this->size());
::std::vector<int> path;
for (int u = v; this->m_from[u] >= 0; u = this->from_vertex(u)) {
path.push_back(this->m_from[u]);
}
::std::ranges::reverse(path);
return path;
}
};
template <::std::ranges::range R1, ::std::ranges::range R2, typename F>
shortest_path_tree(R1&&, R2&&, const F&) -> shortest_path_tree<::std::ranges::range_value_t<R1>, F>;
}
#line 15 "tools/naive_dijkstra.hpp"
namespace tools {
template <bool Directed, typename T>
class naive_dijkstra {
public:
struct edge {
int from;
int to;
T cost;
};
private:
int m_size;
::std::vector<edge> m_edges;
::std::vector<int> m_graph;
public:
naive_dijkstra() = default;
explicit naive_dijkstra(const int n) : m_size(n), m_graph(n * n, -1) {
}
int size() const {
return this->m_size;
}
int add_edge(int u, int v, const T w) {
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
assert(w >= 0);
if constexpr (!Directed) {
::std::tie(u, v) = ::std::minmax({u, v});
}
this->m_edges.push_back({u, v, w});
if (this->m_graph[u * this->size() + v] < 0 || w < this->m_edges[this->m_graph[u * this->size() + v]].cost) {
this->m_graph[u * this->size() + v] = this->m_edges.size() - 1;
if constexpr (!Directed) {
this->m_graph[v * this->size() + u] = this->m_edges.size() - 1;
}
}
return this->m_edges.size() - 1;
}
const edge& get_edge(const int k) const & {
assert(0 <= k && k < ::std::ssize(this->m_edges));
return this->m_edges[k];
}
edge get_edge(const int k) && {
assert(0 <= k && k < ::std::ssize(this->m_edges));
return ::std::move(this->m_edges[k]);
}
const ::std::vector<edge>& edges() const & {
return this->m_edges;
}
::std::vector<edge> edges() && {
return ::std::move(this->m_edges);
}
template <bool Restore = false>
auto query(const int s) const {
assert(0 <= s && s < this->size());
::std::vector<T> dist(this->size(), ::std::numeric_limits<T>::max());
dist[s] = 0;
::std::vector<int> prev(Restore ? this->size() : 0, -1);
::std::vector<int> Q(this->size());
::std::iota(Q.begin(), Q.end(), 0);
while (!Q.empty()) {
const auto min_it = ::std::ranges::min_element(Q, ::tools::less_by([&](const auto v) { return dist[v]; }));
const auto here = *min_it;
if (dist[here] == ::std::numeric_limits<T>::max()) break;
::std::iter_swap(min_it, ::std::prev(Q.end()));
Q.pop_back();
for (const auto next : Q) {
const auto edge_id = this->m_graph[here * this->size() + next];
if (edge_id >= 0 && ::tools::chmin(dist[next], dist[here] + this->m_edges[edge_id].cost)) {
if constexpr (Restore) {
prev[next] = edge_id;
}
}
}
}
if constexpr (Restore) {
return ::tools::shortest_path_tree(dist, prev, [&](const auto e, const auto v) {
return this->m_edges[e].from ^ (Directed ? 0 : this->m_edges[e].to ^ v);
});
} else {
return dist;
}
}
};
}