From 8d97766c3e6ff63fc0754d2819c3a8409ba0fdcf Mon Sep 17 00:00:00 2001 From: ia7ck <23146842+ia7ck@users.noreply.github.com> Date: Sun, 23 Aug 2026 00:46:33 +0900 Subject: [PATCH 1/2] refactoring detect cycle undirected --- .../examples/cycle_detection_undirected.rs | 49 +++++++++ .../judge_cycle_detection_undirected.rs | 102 ++++++++++++++++++ libs/detect_cycle/src/lib.rs | 87 +++++++++------ 3 files changed, 205 insertions(+), 33 deletions(-) create mode 100644 libs/detect_cycle/examples/cycle_detection_undirected.rs create mode 100644 libs/detect_cycle/examples/judge_cycle_detection_undirected.rs diff --git a/libs/detect_cycle/examples/cycle_detection_undirected.rs b/libs/detect_cycle/examples/cycle_detection_undirected.rs new file mode 100644 index 00000000..6be16d4c --- /dev/null +++ b/libs/detect_cycle/examples/cycle_detection_undirected.rs @@ -0,0 +1,49 @@ +// problem: https://judge.yosupo.jp/problem/cycle_detection_undirected +// judge_program_rs: ./judge_cycle_detection_undirected.rs + +use detect_cycle::detect_cycle_undirected; +use proconio::input; + +fn main() { + input! { + n: usize, + m: usize, + edges: [(usize, usize); m], + } + let Some(cycle) = detect_cycle_undirected(n, &edges) else { + println!("-1"); + return; + }; + + let (u, v) = edges[cycle[0]]; + let mut current = if cycle.len() == 1 { + u + } else { + let (next_u, next_v) = edges[cycle[1]]; + if v == next_u || v == next_v { u } else { v } + }; + let mut vertices = Vec::with_capacity(cycle.len()); + for &edge_id in &cycle { + vertices.push(current); + let (u, v) = edges[edge_id]; + current = if current == u { v } else { u }; + } + + println!("{}", cycle.len()); + println!( + "{}", + vertices + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(" ") + ); + println!( + "{}", + cycle + .iter() + .map(|e| e.to_string()) + .collect::>() + .join(" ") + ); +} diff --git a/libs/detect_cycle/examples/judge_cycle_detection_undirected.rs b/libs/detect_cycle/examples/judge_cycle_detection_undirected.rs new file mode 100644 index 00000000..3b90f5ab --- /dev/null +++ b/libs/detect_cycle/examples/judge_cycle_detection_undirected.rs @@ -0,0 +1,102 @@ +use proconio::{ + input, + source::{Source, once::OnceSource}, +}; + +use std::env; +use std::fs::File; +use std::io; +use std::io::{BufRead, BufReader}; + +struct Input { + n: usize, + m: usize, + edges: Vec<(usize, usize)>, +} + +enum Output { + NotFound, + Found { + vertices: Vec, + edge_ids: Vec, + }, +} + +fn read_input(input: impl BufRead) -> Input { + let mut source = OnceSource::new(input); + input! { + from &mut source, + n: usize, + m: usize, + edges: [(usize, usize); m], + } + assert!(source.is_empty()); + Input { n, m, edges } +} + +fn read_output(output: impl BufRead) -> Output { + let mut source = OnceSource::new(output); + input! { + from &mut source, + len: isize, + } + if len < 0 { + assert_eq!(len, -1); + assert!(source.is_empty()); + return Output::NotFound; + } + + let len = len as usize; + assert!(len >= 1); + input! { + from &mut source, + vertices: [usize; len], + edge_ids: [usize; len], + } + assert!(source.is_empty()); + Output::Found { vertices, edge_ids } +} + +fn validate_cycle(input: &Input, vertices: &[usize], edge_ids: &[usize]) { + let len = vertices.len(); + assert_eq!(edge_ids.len(), len); + + let mut seen_vertices = vec![false; input.n]; + let mut seen_edges = vec![false; input.m]; + for i in 0..len { + let vertex = vertices[i]; + let next_vertex = vertices[(i + 1) % len]; + let edge_id = edge_ids[i]; + + assert!(vertex < input.n); + assert!(!seen_vertices[vertex]); + seen_vertices[vertex] = true; + + assert!(edge_id < input.m); + assert!(!seen_edges[edge_id]); + seen_edges[edge_id] = true; + + let (u, v) = input.edges[edge_id]; + assert!((u == vertex && v == next_vertex) || (u == next_vertex && v == vertex)); + } +} + +fn main() -> io::Result<()> { + let args: Vec = env::args().collect(); + assert_eq!(args.len(), 4); + let (input, my_output, expected_output) = (&args[1], &args[2], &args[3]); + + let input = read_input(BufReader::new(File::open(input)?)); + let my_output = read_output(BufReader::new(File::open(my_output)?)); + let expected_output = read_output(BufReader::new(File::open(expected_output)?)); + + match (my_output, expected_output) { + (Output::NotFound, Output::NotFound) => {} + (Output::Found { vertices, edge_ids }, Output::Found { .. }) => { + validate_cycle(&input, &vertices, &edge_ids) + } + _ => panic!("cycle existence does not match the expected output"), + } + + Ok(()) +} diff --git a/libs/detect_cycle/src/lib.rs b/libs/detect_cycle/src/lib.rs index 4dcac88f..8b4a9e77 100644 --- a/libs/detect_cycle/src/lib.rs +++ b/libs/detect_cycle/src/lib.rs @@ -32,23 +32,26 @@ pub fn detect_cycle_undirected(n: usize, edges: &[(usize, usize)]) -> Option> { fn dfs( curr: usize, - prev: usize, + prev_edge: Option, g: &[Vec<(usize, usize)>], - seen: &mut Vec, - parent: &mut Vec<(usize, usize)>, - ) -> Option<(usize, usize)> { - seen[curr] = true; + depth: &mut [Option], + path: &mut Vec, + ) -> Option> { + depth[curr] = Some(path.len()); for &(nxt, idx) in &g[curr] { - if nxt == prev { + if Some(idx) == prev_edge { continue; } - if seen[nxt] { - return Some((nxt, curr)); + if let Some(nxt_depth) = depth[nxt] { + let mut cycle = path[nxt_depth..].to_vec(); + cycle.push(idx); + return Some(cycle); } - parent[nxt] = (curr, idx); - if let Some((start, end)) = dfs(nxt, curr, g, seen, parent) { - return Some((start, end)); + path.push(idx); + if let Some(cycle) = dfs(nxt, Some(idx), g, depth, path) { + return Some(cycle); } + path.pop(); } None } @@ -58,31 +61,15 @@ pub fn detect_cycle_undirected(n: usize, edges: &[(usize, usize)]) -> Option Option Date: Sun, 23 Aug 2026 00:47:18 +0900 Subject: [PATCH 2/2] stack unlimited --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38dedffe..7ad06424 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,9 @@ jobs: - name: Release build run: cargo build --release --examples - name: oj test - run: cargo run --release --bin oj_test + run: | + ulimit -s unlimited + cargo run --release --bin oj_test publish-doc: runs-on: ubuntu-latest