diff --git a/aoj/GRL/GRL5D/main.cpp b/aoj/GRL/GRL5D/main.cpp index 944a5fe4..a023ae3b 100644 --- a/aoj/GRL/GRL5D/main.cpp +++ b/aoj/GRL/GRL5D/main.cpp @@ -1,45 +1,49 @@ -#include -#include +//https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_D -class EulerTrour { - int N; - std::vector> adj; +#include + +class EulerTour { +private: + size_t N; + std::vector> adj; public: - // O(V) - EulerTrour(int size): N(size), adj(size) {} - // O(1) - int size() { + // Time: O(V) + EulerTour(size_t const N = 0): N(N), adj(N) {} + // Time: O(1) + size_t size() const { return N; } - // O(1) - void add_edge(int u, int v) { - throw_if_invalid_index(u); - throw_if_invalid_index(v); + // u = [0,N), v = [0,N) + // Time: O(1) + void add_edge(size_t const u, size_t const v) { + if (u >= N) throw std::out_of_range("u"); + if (v >= N) throw std::out_of_range("v"); adj[u].push_back(v); adj[v].push_back(u); } - // O(E) - void solve(int r, std::vector& tour, std::vector& tin, std::vector& tout) { - throw_if_invalid_index(r); + // r = [0,N) + // Time: O(E) + void solve(size_t r, std::vector& tour, std::vector& tin, std::vector& tout) const { + if (r >= N) throw std::out_of_range("r"); - std::stack> S; + std::stack> S; std::vector visited(N, false); tour.clear(); - tin.assign(N, -1); - tout.assign(N, -1); + tin.assign(N, 2 * N); + tout.assign(N, 2 * N); S.push({r,-1}); while (S.size()) { - int v = S.top().first; + size_t v = S.top().first; int& i = S.top().second; if (i < 0) { visited[v] = true; tour.push_back(v); tin[v] = tour.size() - 1; - } else if (i < adj[v].size()) { - int u = adj[v][i]; + } else if (size_t(i) < adj[v].size()) { + auto u = adj[v][i]; if (!visited[u]) S.push({u,-1}); } else { tour.push_back(v); @@ -49,20 +53,8 @@ class EulerTrour { i++; } } - -private: - void throw_if_invalid_index(int index) { - if (index < 0 || index >= N) throw "index out of range"; - } }; -#include -#include - -// BinaryIndexedTree -// Memory O(N) -// Query O(logN) -// Update O(logN) template class BinaryIndexedTree { public: @@ -132,8 +124,6 @@ class BinaryIndexedTree { }; -#include - using namespace std; int main() { @@ -143,7 +133,7 @@ int main() { int N, Q; cin >> N; - EulerTrour euler_tour(N); + EulerTour euler_tour(N); for (int i = 0; i < N; ++i) { int K, c; cin >> K; @@ -153,7 +143,7 @@ int main() { } } - vector tour, tin, tout; + vector tour, tin, tout; euler_tour.solve(0, tour, tin, tout); BinaryIndexedTree bit(2*N); diff --git a/aoj/GRL/GRL5D/sample1.txt b/aoj/GRL/GRL5D/sample1.txt new file mode 100644 index 00000000..8388911c --- /dev/null +++ b/aoj/GRL/GRL5D/sample1.txt @@ -0,0 +1,15 @@ +6 +2 1 2 +2 3 5 +0 +0 +0 +1 4 +7 +1 1 +0 3 10 +1 2 +0 4 20 +1 3 +0 5 40 +1 4 \ No newline at end of file diff --git a/aoj/GRL/GRL5D/sample2.txt b/aoj/GRL/GRL5D/sample2.txt new file mode 100644 index 00000000..0212d0bd --- /dev/null +++ b/aoj/GRL/GRL5D/sample2.txt @@ -0,0 +1,12 @@ +4 +1 1 +1 2 +1 3 +0 +6 +0 3 1000 +0 2 1000 +0 1 1000 +1 1 +1 2 +1 3 \ No newline at end of file diff --git a/aoj/GRL/GRL5D/sample3.txt b/aoj/GRL/GRL5D/sample3.txt new file mode 100644 index 00000000..c7e7b684 --- /dev/null +++ b/aoj/GRL/GRL5D/sample3.txt @@ -0,0 +1,8 @@ +2 +1 1 +0 +4 +0 1 1 +1 1 +0 1 1 +1 1 \ No newline at end of file diff --git a/lib/cpalgo/tree/euler-tour.hpp b/lib/cpalgo/tree/euler-tour.hpp deleted file mode 100644 index 30b08702..00000000 --- a/lib/cpalgo/tree/euler-tour.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -// Verified -// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_5_D - -#include -#include - -// Euler Tour in Tree -// Memory: O(V + E) -// NOTE: undirected -class EulerTrour { - int N; - std::vector> adj; - -public: - // O(V) - EulerTrour(int n = 0): N(n), adj(n) {} - // O(1) - int size() { - return N; - } - // O(1) - void add_edge(int u, int v) { - throw_if_invalid_index(u); - throw_if_invalid_index(v); - adj[u].push_back(v); - adj[v].push_back(u); - } - // O(E) - void solve(int r, std::vector& tour, std::vector& tin, std::vector& tout) { - throw_if_invalid_index(r); - - std::stack> S; - std::vector visited(N, false); - - tour.clear(); - tin.assign(N, -1); - tout.assign(N, -1); - - S.push({r,-1}); - while (S.size()) { - int v = S.top().first; - int& i = S.top().second; - if (i < 0) { - visited[v] = true; - tour.push_back(v); - tin[v] = tour.size() - 1; - } else if (i < adj[v].size()) { - int u = adj[v][i]; - if (!visited[u]) S.push({u,-1}); - } else { - tour.push_back(v); - tout[v] = tour.size() - 1; - S.pop(); - } - i++; - } - } - -private: - void throw_if_invalid_index(int index) { - if (index < 0 || index >= N) throw "index out of range"; - } -}; \ No newline at end of file diff --git a/lib/cpalgo/tree/euler_tour.hpp b/lib/cpalgo/tree/euler_tour.hpp new file mode 100644 index 00000000..64865d17 --- /dev/null +++ b/lib/cpalgo/tree/euler_tour.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + + +// Euler Tour in Tree +// +// Space: O(V + E) +// +// NOTE: +// - undirected +// - non-loop +// - non-multi-edge +// - it can handle a forest +// +// Verified: +// - https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_D +// +class EulerTour { +private: + size_t N; + std::vector> adj; + +public: + // Time: O(V) + EulerTour(size_t const N = 0): N(N), adj(N) {} + // Time: O(1) + size_t size() const { + return N; + } + // u = [0,N), v = [0,N) + // Time: O(1) + void add_edge(size_t const u, size_t const v) { + if (u >= N) throw std::out_of_range("u"); + if (v >= N) throw std::out_of_range("v"); + adj[u].push_back(v); + adj[v].push_back(u); + } + // r = [0,N) + // Time: O(E) + void solve(size_t r, std::vector& tour, std::vector& tin, std::vector& tout) const { + if (r >= N) throw std::out_of_range("r"); + + std::stack> S; + std::vector visited(N, false); + + tour.clear(); + tin.assign(N, 2 * N); + tout.assign(N, 2 * N); + + S.push({r,-1}); + while (S.size()) { + size_t v = S.top().first; + int& i = S.top().second; + if (i < 0) { + visited[v] = true; + tour.push_back(v); + tin[v] = tour.size() - 1; + } else if (size_t(i) < adj[v].size()) { + auto u = adj[v][i]; + if (!visited[u]) S.push({u,-1}); + } else { + tour.push_back(v); + tout[v] = tour.size() - 1; + S.pop(); + } + i++; + } + } +}; \ No newline at end of file diff --git a/lib/cpalgo/tree/tests/euler_touer_test.cpp b/lib/cpalgo/tree/tests/euler_touer_test.cpp new file mode 100644 index 00000000..9885259b --- /dev/null +++ b/lib/cpalgo/tree/tests/euler_touer_test.cpp @@ -0,0 +1,53 @@ +#include +#include "gtest/gtest.h" +#include "cpalgo/tree/euler_tour.hpp" + +using namespace std; + + +TEST(EulerTourTest, IsEmptyInitially) { + EulerTour solver; + EXPECT_EQ(0ULL, solver.size()); +} + +TEST(EulerTourTest, ShouldComputeEulerTour) { + EulerTour solver(7); + EXPECT_EQ(7ULL, solver.size()); + + solver.add_edge(0, 1); + solver.add_edge(1, 2); + solver.add_edge(1, 3); + solver.add_edge(0, 4); + solver.add_edge(0, 5); + solver.add_edge(5, 6); + + vector tour, tin, tout; + solver.solve(0, tour, tin, tout); + + vector expected_tour = { 0, 1, 2, 2, 3, 3, 1, 4, 4, 5, 6, 6, 5, 0 }; + vector expected_tin = { 0, 1, 2, 4, 7, 9, 10 }; + vector expected_tout = { 13, 6, 3, 5, 8, 12, 11 }; + EXPECT_EQ(expected_tour, tour); + EXPECT_EQ(expected_tin, tin); + EXPECT_EQ(expected_tout, tout); +} + +TEST(EulerTourTest, ShouldHandleAForest) { + EulerTour solver(7); + EXPECT_EQ(7ULL, solver.size()); + + solver.add_edge(0, 1); + solver.add_edge(1, 2); + solver.add_edge(1, 3); + solver.add_edge(5, 6); + + vector tour, tin, tout; + solver.solve(0, tour, tin, tout); + + vector expected_tour = { 0, 1, 2, 2, 3, 3, 1, 0 }; + vector expected_tin = { 0, 1, 2, 4, 14, 14, 14 }; + vector expected_tout = { 7, 6, 3, 5, 14, 14, 14 }; + EXPECT_EQ(expected_tour, tour); + EXPECT_EQ(expected_tin, tin); + EXPECT_EQ(expected_tout, tout); +} \ No newline at end of file diff --git a/lib/main/tree/main-euler-tour.cpp b/lib/main/tree/main-euler-tour.cpp index 37b0576f..e067fee8 100644 --- a/lib/main/tree/main-euler-tour.cpp +++ b/lib/main/tree/main-euler-tour.cpp @@ -1,31 +1,24 @@ -#include -#include -#include -#include -#include +#include #include "template/template-main.hpp" -#include "cpalgo/tree/euler-tour.hpp" +#include "cpalgo/tree/euler_tour.hpp" using namespace std; -EulerTrour solver; + +EulerTour solver; void action_init() { - int size; + size_t size; cin >> size; - if (size < 0) { - cout << "false" << endl; - return; - } - solver = EulerTrour(size); + solver = EulerTour(size); cout << "true" << endl; } void action_edge() { - int u, v; + size_t u, v; cin >> u >> v; - if (u < 0 || u >= solver.size() || - v < 0 || v >= solver.size()) + if (u >= solver.size() || + v >= solver.size()) { cout << "false" << endl; return; @@ -35,19 +28,19 @@ void action_edge() { } void action_solve() { - const int N = solver.size(); - int r; + const size_t N = solver.size(); + size_t r; cin >> r; - if (r < 0 || r >= N) { + if (r >= N) { cout << "false" << endl; return; } - vector tour, tin, tout; + vector tour, tin, tout; solver.solve(r, tour, tin, tout); - const int W = log10(max(1,N)) + 2; - auto dump = [&](const string& header, const vector& v) { + const size_t W = log10(max(size_t(1),N)) + 2; + auto dump = [&](string const& header, vector const& v) { cout << header; - for (int i = 0; i < v.size(); ++i) { + for (size_t i = 0; i < v.size(); ++i) { if (i > 0) cout << " "; cout << setw(W) << v[i]; } @@ -62,5 +55,5 @@ void setup(string& header, map& commands) { header = "Euler Tour"; commands["init"] = { "init {size}", action_init }; commands["edge"] = { "edge {u} {v}", action_edge }; - commands["solve"] = { "solve", action_solve }; + commands["solve"] = { "solve {r}", action_solve }; } \ No newline at end of file