Cod sursa(job #3141311)

Utilizator TincaMateiTinca Matei TincaMatei Data 13 iulie 2023 15:40:12
Problema Ciclu Eulerian Scor 100
Compilator rs Status done
Runda Arhiva educationala Marime 9.36 kb
#![allow(dead_code)]

use std::io::{Read, BufRead, Stdin, BufReader};
use std::fs::File;
use std::str::FromStr;
use std::fmt::Debug;

pub struct InParser<T: Read> {
    reader: BufReader<T>,
    buffer: Vec<u8>,
    cursor: usize,
    eof_flag: bool,
}

impl InParser<Stdin> {
    pub fn from_stdin() -> InParser<Stdin> {
        InParser::new(std::io::stdin())
    }
}

impl InParser<File> {
    pub fn from_filename(name: &str) -> InParser<File> {
        InParser::new(File::open(name)
                      .expect("Failed to open file"))
    }
}

impl<T: Read> InParser<T> {
    pub fn new(reader: T) -> InParser<T> {
        let mut reader = BufReader::new(reader);

        let buffer = reader.fill_buf()
            .expect("Failed to fill buffer")
            .to_vec();
        
        InParser {
            reader,
            buffer,
            cursor: 0,
            eof_flag: false,
        }
    }
    
    pub fn get_current_byte(&mut self) -> u8 {
        if self.cursor < self.buffer.len() {
            return self.buffer[self.cursor]; 
        }
        panic!("Outside of buffer")
    }

    pub fn advance_cursor(&mut self) {
        self.cursor += 1;
        if self.cursor >= self.buffer.len() {
            self.reader.consume(self.buffer.len());
            self.buffer = self.reader.fill_buf()
                .expect("Failed to fill buffer")
                .to_vec();

            self.eof_flag = self.buffer.is_empty();
            self.cursor = 0;
        }
    }

    fn skip_spaces(&mut self) {
        while !self.eof_flag && 
            (self.get_current_byte() == b' ' ||
             self.get_current_byte() == b'\n') {
            
            self.advance_cursor();
        }
    }

    fn get_token(&mut self) -> Vec<u8> {
        let mut token_buf: Vec<u8> = Vec::new();

        self.skip_spaces();

        while !self.eof_flag &&
            self.get_current_byte() != b' ' &&
            self.get_current_byte() != b'\n' {
            
            let byte = self.get_current_byte();
            token_buf.push(byte);

            self.advance_cursor();
        }

        token_buf
    }
   
    pub fn read_string(&mut self) -> String {
        let token = self.get_token();
        
        let strval = std::str::from_utf8(&token)
            .expect("Failed to convert into valid utf8")
            .trim();

        strval.to_string()
    }
    
    pub fn read_number<F: From<i64>>(&mut self) -> F {
        self.skip_spaces();

        let sgn = if self.get_current_byte() == b'-' {
            self.advance_cursor();
            -1
        } else {
            1
        };
        let mut nr = 0;

        while !self.eof_flag && self.get_current_byte().is_ascii_digit() {
            nr = nr * 10 + (self.get_current_byte() - b'0') as i64;
            self.advance_cursor();
        }

        F::from(nr * sgn)
    }

    pub fn read<F>(&mut self) -> F
    where F: FromStr,
          <F as FromStr>::Err: Debug {
        self.read_string().parse::<F>()
            .unwrap()
    }
}

use std::io::{Write, BufWriter, Stdout};

pub struct OutParser<T: Write> {
    writer: BufWriter<T>,
}

impl<T: Write> OutParser<T> {
    pub fn new(writer: T) -> OutParser<T> {
        OutParser {
            writer: BufWriter::new(writer)
        }
    }

    pub fn write<F: ToString>(&mut self, val: F) -> &mut Self {
        self.writer.write(&val.to_string().as_bytes())
            .expect("Failed to write");
        
        self
    }
}

impl OutParser<Stdout> {
    pub fn from_stdout() -> OutParser<Stdout> {
        OutParser::new(std::io::stdout())
    }
}

impl OutParser<File> {
    pub fn from_filename(name: &str) -> OutParser<File> {
        OutParser::new(File::create(name)
                       .expect("Failed to open file"))
    }
}

pub trait Edge {
    fn to(&self, from: usize) -> usize;
}

pub trait BidirectionalEdge: Edge {
    fn as_pair(&self) -> (usize, usize);
}

#[derive(Debug)]
pub struct Graph<V, E>
where V: Default,
      E: Edge {
    pub nodes: Vec<V>,
    pub edges: Vec<E>,
    pub adj_list: Vec<Vec<usize>>,
}

impl<V, E> Graph<V, E> 
where V: Default,
      E: Edge {
    
    pub fn from_edges<T, F>(
        v: usize, 
        edges: Vec<T>, 
        transf: F,
        undirected: bool
    ) -> Graph<V, E>
    where T: BidirectionalEdge,
          F: Fn(T) -> E {
        let mut nodes = Vec::with_capacity(v);
        for _ in 0..v {
            nodes.push(V::default());
        }

        let mut capacity = vec![0; v];
        for e in &edges {
            let (a, b) = e.as_pair();
            capacity[a] += 1;
            if undirected {
                capacity[b] += 1;
            }
        }

        let mut adj_list: Vec<Vec<usize>> = Vec::with_capacity(v);
        for i in 0..v {
            adj_list.push(Vec::with_capacity(capacity[i]));
        }

        for id in 0..edges.len() {
            let edge = &edges[id];
            let (a, b) = edge.as_pair();
            adj_list[a].push(id);

            if undirected {
                adj_list[b].push(id);
            }
        }
        
        let edges: Vec<E> = edges.into_iter().map(transf).collect();

        Graph::<V, E> {
            nodes,
            edges,
            adj_list
        }
    }

    pub fn v(&self) -> usize { self.nodes.len() }
    pub fn e(&self) -> usize { self.edges.len() }
}

impl Edge for usize {
    fn to(&self, _: usize) -> usize { *self }
}

impl Edge for (usize, usize) {
    fn to(&self, from: usize) -> usize {
        return self.0 ^ self.1 ^ from;
    }
}

impl BidirectionalEdge for (usize, usize) {
    fn as_pair(&self) -> (usize, usize) {
        return *self;
    }
}

struct EulerianCycleSolver<'a, V, E>
where V: Default,
      E: Edge {
    
    graph: &'a Graph<V, E>,
    used_edge: Vec<bool>,
    last_edge: Vec<usize>,
    result: Vec<usize>,
}

impl<'a, V, E> EulerianCycleSolver<'a, V, E>
where V: Default,
      E: Edge {
    
    pub fn eulerian_dfs(&mut self, node: usize) {
        while self.last_edge[node] < self.graph.adj_list[node].len() {
            let cnt_edge = self.last_edge[node];
            let id = self.graph.adj_list[node][cnt_edge];
            
            if !self.used_edge[id] {
                let other = self.graph.edges[id].to(node);
                self.used_edge[id] = true;

                self.eulerian_dfs(other);
            }

            self.last_edge[node] += 1; 
        }

        self.result.push(node);
    }
}

pub fn eulerian_path<V, E>(
    graph: &Graph<V, E>,
    undirected: bool,
    cycle: bool
) -> Option<Vec<usize>>
where V: Default,
      E: Edge{
    
    let mut degree = vec![0; graph.v()];

    for node in 0..graph.v() {
        for it in &graph.adj_list[node] {
            let edge = &graph.edges[*it];
            degree[edge.to(node)] += 1;
        }
    }

    let mut start_node = 0;
    let mut cnt_even = 0;
    let mut cnt_pos = 0;
    let mut cnt_neg = 0;

    for node in 0..graph.v() {
        if undirected && degree[node] % 2 == 1 {
            start_node = node;
            cnt_even += 1;
        } else if !undirected && degree[node] < graph.adj_list[node].len() {
            start_node = node;
            cnt_pos += 1;
        } else if !undirected && degree[node] > graph.adj_list[node].len() {
            cnt_neg += 1;
        }
    }

    if undirected {
        if cnt_even > 2 {
            return None;
        }
        if cycle && cnt_even > 0 {
            return None;
        }
    } else {
        if cnt_pos > 1 || cnt_neg > 1 {
            return None;
        }
        if cycle && (cnt_pos > 0 || cnt_neg > 0) {
            return None;
        }
    }
    
    let mut solver = EulerianCycleSolver {
        graph,
        used_edge: vec![false; graph.e()],
        last_edge: vec![0; graph.v()],
        result: Vec::with_capacity(graph.e() + 1),
    };

    solver.eulerian_dfs(start_node);

    if solver.result.len() != graph.e() + 1 {
        None
    } else {
        if !undirected {
            solver.result.reverse();
        }
        Some(solver.result)
    }
}

fn solve_test<I: Read, O: Write>(fin: &mut InParser<I>, fout: &mut OutParser<O>) {
    let (n, m) = (fin.read(), fin.read());
    let mut edges: Vec<(usize, usize)> = Vec::with_capacity(m);

    for _ in 0..m {
        // should use read_number
        let (a, b): (usize, usize) = (fin.read::<usize>() - 1, 
                                      fin.read::<usize>() - 1);
        edges.push((a, b));
    }

    let graph = Graph::<(), (usize, usize)>::from_edges(
        n,
        edges,
        |x| { x },
        true
    );

    let cycle = eulerian_path(
        &graph,
        true,
        true
    );

    match cycle {
    None => {
        fout.write("-1");
    }
    Some(result) => {
        for e in result {
            fout.write(e + 1);
            fout.write(" ");
        }
    }
    }
}

// Run a sample with the given input and check with the correct output.
fn try_sample(input: &[u8], ok: &str) {
    use std::io::Cursor;

    let mut output = Vec::<u8>::new();

    solve_test(&mut InParser::new(BufReader::new(Cursor::new(input))),
               &mut OutParser::new(BufWriter::new(&mut output)));

    assert_eq!(std::str::from_utf8(&output).unwrap(), ok);
}

// Run the first sample of the problem.
// dang it, I can't test these >:(
fn sample_1() {
    try_sample(br#"1 2"#, r#"3"#);
}

fn main() {
    //sample_1();
    
    solve_test(&mut InParser::from_filename("ciclueuler.in"),
               &mut OutParser::from_filename("ciclueuler.out"));

}