辺の列を読み込んで保持する入力中間型
lib/graph/edge_input.hpp
インクルード
#include "graph/edge_input.hpp"
クラス
| 名前 | 説明 |
|---|---|
edge_input |
辺の列を読み込んで保持する入力中間型 |
検証
- test/aoj/challenge/2270.test.cpp
- test/aoj/challenge/2871.test.cpp
- test/aoj/challenge/2891.test.cpp
- test/aoj/challenge/2995.test.cpp
- test/aoj/challenge/3163.test.cpp
- test/aoj/course/GRL_1_A.test.cpp
- test/aoj/course/GRL_1_B.test.cpp
- test/aoj/course/GRL_2_A.test.cpp
- test/aoj/grl/articulation_points.test.cpp
- test/aoj/grl/bridges.test.cpp
- test/aoj/grl/cycle.test.cpp
- test/aoj/grl/scc.test.cpp
- test/aoj/grl/topological_sort.test.cpp
- test/yosupo/graph/cycle_detection.test.cpp
- test/yosupo/graph/cycle_detection_undirected.test.cpp
- test/yosupo/graph/dominator_tree.test.cpp
- test/yosupo/graph/maximum_independent_set.test.cpp
- test/yosupo/graph/shortest_path.test.cpp
- test/yosupo/graph/shortest_path_traced.test.cpp
- test/yosupo/graph/strongly_connected_components.test.cpp
- test/yosupo/tree/frequency_table_of_tree_distance.test.cpp
- test/yosupo/tree/jump_on_tree.test.cpp
- test/yosupo/tree/lowest_common_ancestor.test.cpp
- test/yosupo/tree/tree_diameter.test.cpp
- test/yosupo/tree/vertex_add_path_sum.test.cpp
- test/yosupo/tree/vertex_add_subtree_sum.test.cpp
- test/yukicoder/0901.test.cpp
依存するヘッダ(1)
-
グラフ表現 (list_graph / csr_graph)
lib/graph/graph.hpp
検証プログラム(27)
-
test/aoj/challenge/2270.test.cpp
test/aoj/challenge/2270.test.cpp -
test/aoj/challenge/2871.test.cpp
test/aoj/challenge/2871.test.cpp -
test/aoj/challenge/2891.test.cpp
test/aoj/challenge/2891.test.cpp -
test/aoj/challenge/2995.test.cpp
test/aoj/challenge/2995.test.cpp -
test/aoj/challenge/3163.test.cpp
test/aoj/challenge/3163.test.cpp -
test/aoj/course/GRL_1_A.test.cpp
test/aoj/course/GRL_1_A.test.cpp -
test/aoj/course/GRL_1_B.test.cpp
test/aoj/course/GRL_1_B.test.cpp -
test/aoj/course/GRL_2_A.test.cpp
test/aoj/course/GRL_2_A.test.cpp -
test/aoj/grl/articulation_points.test.cpp
test/aoj/grl/articulation_points.test.cpp -
test/aoj/grl/bridges.test.cpp
test/aoj/grl/bridges.test.cpp -
test/aoj/grl/cycle.test.cpp
test/aoj/grl/cycle.test.cpp -
test/aoj/grl/scc.test.cpp
test/aoj/grl/scc.test.cpp -
test/aoj/grl/topological_sort.test.cpp
test/aoj/grl/topological_sort.test.cpp -
test/yosupo/graph/cycle_detection.test.cpp
test/yosupo/graph/cycle_detection.test.cpp -
test/yosupo/graph/cycle_detection_undirected.test.cpp
test/yosupo/graph/cycle_detection_undirected.test.cpp -
test/yosupo/graph/dominator_tree.test.cpp
test/yosupo/graph/dominator_tree.test.cpp -
test/yosupo/graph/maximum_independent_set.test.cpp
test/yosupo/graph/maximum_independent_set.test.cpp -
test/yosupo/graph/shortest_path.test.cpp
test/yosupo/graph/shortest_path.test.cpp -
test/yosupo/graph/shortest_path_traced.test.cpp
test/yosupo/graph/shortest_path_traced.test.cpp -
test/yosupo/graph/strongly_connected_components.test.cpp
test/yosupo/graph/strongly_connected_components.test.cpp -
test/yosupo/tree/frequency_table_of_tree_distance.test.cpp
test/yosupo/tree/frequency_table_of_tree_distance.test.cpp -
test/yosupo/tree/jump_on_tree.test.cpp
test/yosupo/tree/jump_on_tree.test.cpp -
test/yosupo/tree/lowest_common_ancestor.test.cpp
test/yosupo/tree/lowest_common_ancestor.test.cpp -
test/yosupo/tree/tree_diameter.test.cpp
test/yosupo/tree/tree_diameter.test.cpp -
test/yosupo/tree/vertex_add_path_sum.test.cpp
test/yosupo/tree/vertex_add_path_sum.test.cpp -
test/yosupo/tree/vertex_add_subtree_sum.test.cpp
test/yosupo/tree/vertex_add_subtree_sum.test.cpp -
test/yukicoder/0901.test.cpp
test/yukicoder/0901.test.cpp
実装
#pragma once
#include <iostream>
#include <type_traits>
#include <vector>
#include "graph/graph.hpp"
/// @brief 辺の列を読み込んで保持する入力中間型
/// @tparam T 辺の重みの型。`void` で重みなし(入力から重みを読まない)。
///
/// 標準入力から `(from, to[, weight])` を origin 補正して読み込み、
/// グラフ表現に依存しない生の辺データとして保持する。
/// `build_directed(graph)` / `build_undirected(graph)` で任意のグラフ型に
/// 流し込める(`add_edge` / `add_edges` を持つ型なら何でも受け取れる)。
/// @complexity 辺数を $E$ として入力・構築は $O(E)$
template <class T>
struct edge_input {
/// 重みの実体型: `void` は空タグ Unweighted に正規化する
/// @complexity コンパイル時定数で実行時計算量はない
static constexpr bool weighted = !std::is_void_v<T>;
/// @brief 重みの実体型
/// @complexity 型エイリアスで実行時計算量はない
using weight_type = std::conditional_t<weighted, T, Unweighted>;
/// @brief 入力した1本の辺
/// @complexity データ型で実行時計算量はない
struct raw_edge {
/// @brief 辺の始点と終点
/// @complexity $O(1)$ で参照可能
int from, to;
/// @brief 辺の重み
/// @complexity $O(1)$ で参照可能
[[no_unique_address]] weight_type weight;
};
/// @brief 空の辺列を構築する
/// @complexity $O(1)$
edge_input() = default;
/// @brief 標準入力から m 本の辺を読み込む(頂点番号は origin から)
/// @complexity $O(m)$
explicit edge_input(int m, int origin = 1) { input(m, origin); }
/// @brief 標準入力から m 本の辺を追加で読み込む
/// @complexity $O(m)$
void input(int m, int origin = 1) {
edges.reserve(edges.size() + m);
for (int i = 0; i < m; ++i) {
int from, to;
std::cin >> from >> to;
if constexpr (weighted) {
T weight;
std::cin >> weight;
edges.emplace_back(from - origin, to - origin, weight);
} else {
edges.emplace_back(from - origin, to - origin, weight_type());
}
}
}
/// @brief 1 本の辺を追加する
/// @complexity 償却 $O(1)$
void emplace(int from, int to, weight_type weight = weight_type()) { edges.emplace_back(from, to, weight); }
/// @brief 保持する辺数を返す
/// @complexity $O(1)$
int size() const { return (int)edges.size(); }
/// @brief i番目の辺を返す
/// @complexity $O(1)$
const raw_edge &operator[](int i) const { return edges[i]; }
/// @brief 先頭iteratorを返す
/// @complexity $O(1)$
auto begin() const { return edges.begin(); }
/// @brief 終端iteratorを返す
/// @complexity $O(1)$
auto end() const { return edges.end(); }
/// @brief 有向辺として graph に流し込む(add_edge を呼ぶ)
/// @complexity $O(E)$
template <class G>
void build_directed(G &g) const {
for (auto &e : edges) {
if constexpr (weighted) g.add_edge(e.from, e.to, e.weight);
else g.add_edge(e.from, e.to);
}
}
/// @brief 無向辺として graph に流し込む(add_edges を呼ぶ)
/// @complexity $O(E)$
template <class G>
void build_undirected(G &g) const {
for (auto &e : edges) {
if constexpr (weighted) g.add_edges(e.from, e.to, e.weight);
else g.add_edges(e.from, e.to);
}
}
/// @brief n 頂点の有向グラフを構築して返す
/// @tparam GraphT 構築するグラフ型テンプレート(`csr_graph`(既定)/ `list_graph`)
///
/// `csr_graph` の場合は辺数(有向辺 = m 本)を予約してから `build()` まで行う。
/// @complexity $O(V+E)$
template <template <class> class GraphT = csr_graph>
GraphT<T> to_directed(int n) const {
GraphT<T> g(n);
if constexpr (std::is_same_v<GraphT<T>, csr_graph<T>>) g.reserve_edges(size(), size());
build_directed(g);
if constexpr (std::is_same_v<GraphT<T>, csr_graph<T>>) g.build();
return g;
}
/// @brief n 頂点の無向グラフを構築して返す
/// @tparam GraphT 構築するグラフ型テンプレート(`csr_graph`(既定)/ `list_graph`)
///
/// `csr_graph` の場合は辺数(辺 ID = m 個・有向辺 = 2m 本)を予約してから `build()` まで行う。
/// @complexity $O(V+E)$
template <template <class> class GraphT = csr_graph>
GraphT<T> to_undirected(int n) const {
GraphT<T> g(n);
if constexpr (std::is_same_v<GraphT<T>, csr_graph<T>>) g.reserve_edges(size(), 2 * size());
build_undirected(g);
if constexpr (std::is_same_v<GraphT<T>, csr_graph<T>>) g.build();
return g;
}
private:
std::vector<raw_edge> edges;
};