diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 47570f79..97843eb4 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -63,6 +63,8 @@ "tests/library_checker_aizu_tests/graphs/dijkstra_lib_checker.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/graphs/directed_cycle.test.cpp": "2026-01-17 13:05:42 -0700", "tests/library_checker_aizu_tests/graphs/enumerate_triangles.test.cpp": "2025-08-06 16:18:37 -0600", +"tests/library_checker_aizu_tests/graphs/euler_walk_directed.test.cpp": "2026-02-26 13:17:25 -0700", +"tests/library_checker_aizu_tests/graphs/euler_walk_undirected.test.cpp": "2026-02-26 13:17:25 -0700", "tests/library_checker_aizu_tests/graphs/hopcroft_karp_aizu.test.cpp": "2025-12-11 21:47:53 +0000", "tests/library_checker_aizu_tests/graphs/hopcroft_karp_lib_checker.test.cpp": "2025-12-11 21:47:53 +0000", "tests/library_checker_aizu_tests/graphs/mst.test.cpp": "2026-01-22 10:08:22 -0700", diff --git a/library/graphs/euler_path.hpp b/library/graphs/euler_path.hpp new file mode 100644 index 00000000..ad9173b0 --- /dev/null +++ b/library/graphs/euler_path.hpp @@ -0,0 +1,28 @@ +#pragma once +//! @code +//! vector>> adj(n); +//! rep(i, 0, m) { +//! int u, v; +//! cin >> u >> v; +//! u--, v--; +//! adj[u] += {v, i}; +//! } +//! vector path = euler_path(adj, m, source); +//! @endcode +//! @time O(n + m) +//! @space O(n + m) +vector euler_path(auto& adj, int m, int s) { + vi vis(m); + vector path; + auto dfs = [&](auto&& self, int u, int eu) -> void { + while (!empty(adj[u])) { + auto [v, ev] = adj[u].back(); + adj[u].pop_back(); + if (!vis[ev]) vis[ev] = 1, self(self, v, ev); + } + path.emplace_back(u, eu); + }; + dfs(dfs, s, -1); + ranges::reverse(path); + return path; +} diff --git a/tests/library_checker_aizu_tests/graphs/euler_walk_directed.test.cpp b/tests/library_checker_aizu_tests/graphs/euler_walk_directed.test.cpp new file mode 100644 index 00000000..92233f2a --- /dev/null +++ b/tests/library_checker_aizu_tests/graphs/euler_walk_directed.test.cpp @@ -0,0 +1,46 @@ +#define PROBLEM \ + "https://judge.yosupo.jp/problem/eulerian_trail_directed" +#include "../template.hpp" +#include "../../../library/graphs/euler_path.hpp" +int main() { + cin.tie(0)->sync_with_stdio(0); + int t; + cin >> t; + while (t--) { + int n, m; + cin >> n >> m; + vector> adj(n); + vi deg(n); + int s = -1; + rep(i, 0, m) { + int u, v; + cin >> u >> v; + s = u; + adj[u].emplace_back(v, i); + deg[u]++; + deg[v]--; + } + if (*max_element(all(deg)) >= 2) { + cout << "No" << '\n'; + continue; + } + if (ranges::count(deg, 1) >= 2) { + cout << "No" << '\n'; + continue; + } + auto it = ranges::find(deg, 1); + if (it != end(deg)) s = it - begin(deg); + else if (s == -1) s = 0; + vector res = euler_path(adj, m, s); + if (ssize(res) != m + 1) { + cout << "No" << '\n'; + continue; + } + cout << "Yes" << '\n'; + rep(i, 0, sz(res)) cout << res[i].first << ' '; + cout << '\n'; + rep(i, 1, sz(res)) cout << res[i].second << ' '; + cout << '\n'; + } + return 0; +} diff --git a/tests/library_checker_aizu_tests/graphs/euler_walk_undirected.test.cpp b/tests/library_checker_aizu_tests/graphs/euler_walk_undirected.test.cpp new file mode 100644 index 00000000..8de78f92 --- /dev/null +++ b/tests/library_checker_aizu_tests/graphs/euler_walk_undirected.test.cpp @@ -0,0 +1,43 @@ +#define PROBLEM \ + "https://judge.yosupo.jp/problem/eulerian_trail_undirected" +#include "../template.hpp" +#include "../../../library/graphs/euler_path.hpp" +int main() { + cin.tie(0)->sync_with_stdio(0); + int t; + cin >> t; + while (t--) { + int n, m; + cin >> n >> m; + vector> adj(n); + vi deg(n); + int s = -1; + rep(i, 0, m) { + int u, v; + cin >> u >> v; + s = u; + adj[u].emplace_back(v, i); + adj[v].emplace_back(u, i); + deg[u] ^= 1; + deg[v] ^= 1; + } + if (ranges::count(deg, 1) > 2) { + cout << "No" << '\n'; + continue; + } + auto it = ranges::find(deg, 1); + if (it != end(deg)) s = it - begin(deg); + else if (s == -1) s = 0; + vector res = euler_path(adj, m, s); + if (ssize(res) != m + 1) { + cout << "No" << '\n'; + continue; + } + cout << "Yes" << '\n'; + rep(i, 0, sz(res)) cout << res[i].first << ' '; + cout << '\n'; + rep(i, 1, sz(res)) cout << res[i].second << ' '; + cout << '\n'; + } + return 0; +}