Problem:
Score : 300 points

Problem Statement

You are given an undirected connected graph with N vertices and M edges that does not contain self-loops and double edges.

The i-th edge (1 \leq i \leq M) connects Vertex a_i and Vertex b_i.

An edge whose removal disconnects the graph is called a bridge.

Find the number of the edges that are bridges among the M edges.

Notes

A self-loop is an edge i such that a_i=b_i (1 \leq i \leq M).

Double edges are a pair of edges i,j such that a_i=a_j and b_i=b_j (1 \leq i<j \leq M).

An undirected graph is said to be connected when there exists a path between every pair of vertices.

Constraints

2 \leq N \leq 50

N-1 \leq M \leq min(N(N−1)⁄2,50)

1 \leq a_i<b_i \leq N

The given graph does not contain self-loops and double edges.

The given graph is connected.

Input

Input is given from Standard Input in the following format:

N M
a_1 b_1
a_2 b_2
:
a_M b_M

Output

Print the number of the edges that are bridges among the M edges.

Sample Input 1

7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7

Sample Output 1

4

The figure below shows the given graph:

The edges shown in red are bridges. There are four of them.

Sample Input 2

3 3
1 2
1 3
2 3

Sample Output 2

0

It is possible that there is no bridge.

Sample Input 3

6 5
1 2
2 3
3 4
4 5
5 6

Sample Output 3

5

It is possible that every edge is a bridge.

Solution in Rust (1.15.1) (judge verdict: Accepted)

use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

type Weight = i32;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

fn bridge(g: &Graph) -> Edges {
    let n = g.len();
    let mut bridges: Edges = vec![];
    let mut order = vec![None; n];
    let mut roots = vec![];
    let mut st = vec![];
    let mut connect = vec![vec![]];
    let mut cnt = 0;
    for i in 0..n {
        if order[i] != None {
            continue;
        }
        bridge_dfs(
            g,
            &Edge::new(std::usize::MAX, i, i, 0),
            &mut bridges,
            &mut connect,
            &mut roots,
            &mut st,
            &mut order,
            &mut cnt,
        );
        bridges.pop();
    }
    return bridges;
}

fn bridge_dfs(
    g: &Graph,
    edge: &Edge,
    bridges: &mut Edges,
    connect: &mut Vec<Vec<usize>>,
    roots: &mut Vec<usize>,
    st: &mut Vec<usize>,
    order: &mut Vec<Option<usize>>,
    cnt: &mut usize,
) {
    let parent_index = edge.index;
    let from = edge.dest;
    order[from] = Some(*cnt);
    *cnt += 1;
    st.push(from);
    roots.push(from);
    for edge in g[from].iter() {
        if parent_index == edge.index {
            continue;
        }
        let to = edge.dest;
        if order[to] == None {
            bridge_dfs(&g, edge, bridges, connect, roots, st, order, cnt);
        } else {
            while order[*roots.last().unwrap()].unwrap() > order[to].unwrap() {
                roots.pop();
            }
        }
    }
    if from == *roots.last().unwrap() {
        bridges.push(edge.clone());
        connect.push(vec![]);
        loop {
            let w = *st.last().unwrap();
            st.pop();
            connect.last_mut().unwrap().push(w);
            if from == w {
                break;
            }
        }
        roots.pop();
    }
}

fn main() {
    let n: usize = read();
    let m: usize = read();
    let mut g = graph_new(n);
    let mut e = 0;
    for _ in 0..m {
        let a = read::<usize>() - 1;
        let b = read::<usize>() - 1;
        add_bi_edge(&mut g, &mut e, a, b, 0);
    }
    let bridges = bridge(&g);
    println!("{}", bridges.len());
}