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 C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;

namespace ABC
{
    class ABC075C
    {
        public class Edge
        {
            public int a;
            public int b;
            public Edge() { a = 0; b = 0; }
            public Edge(int _a, int _b)
            {
                a = _a;
                b = _b;
            }
        }
        //隣接行列
        static bool[,] graph = null;

        //訪れた点のリストメモ
        static bool[] visitedPoints = null;

        static int NUM_POINT = 0;
        static int NUM_EDGE = 0;

        static void Main(string[] args)
        {
            string[] str = Console.ReadLine().Split(' ');
            NUM_POINT = int.Parse(str[0]);//点の数N
            NUM_EDGE = int.Parse(str[1]);//辺の数M
            var EdgeList = new List<Edge>(NUM_EDGE);
            graph = new bool[NUM_POINT, NUM_POINT];//初期化.点の数の自乗
            for(int i = 0; i < NUM_EDGE; ++i)//辺の数だけ
            {
                string[] s = Console.ReadLine().Split(' ');
                int a = int.Parse(s[0]);
                int b = int.Parse(s[1]);
                //a,bともに1以上。配列のindexに合わせるため、1引く
                a--;
                b--;
                EdgeList.Add(new Edge(a, b));
                graph[a,b] = graph[b,a] = true;//隣接行列をマーク
            }

            //DFSで訪れた点のリスト。trueなら訪れた
            visitedPoints = new bool[NUM_POINT];

            //橋となった数。答え。
            int bridgeCount = 0;

            for(int i = 0; i < NUM_EDGE; ++i)//全ての辺に対して
            {
                //キャッシュであるvisitedを初期化
                for(int j = 0; j < NUM_POINT; j++) { visitedPoints[j] = false; }

                //その辺をカットする
                graph[EdgeList[i].a,EdgeList[i].b] = graph[EdgeList[i].b,EdgeList[i].a] = false;

                //適当な点からスタートして、行ける点を全部マーキング
                DFS(0);

                //点を全部調べる。行けない点が存在するかどうか(マーキングされていない点があったか)チェック
                for (int j = 0; j < NUM_POINT; ++j)
                {
                    if(visitedPoints[j] == false)
                    {
                        //行けない点があった。よって、切った辺はbridgeだった。
                        bridgeCount++;
                        break;
                    }
                }

                //これでその辺に対する操作は終了
                //次回のために、切った辺をつなぎ直す
                graph[EdgeList[i].a, EdgeList[i].b] = graph[EdgeList[i].b, EdgeList[i].a] = true;
            }

            Console.WriteLine("{0}", bridgeCount);
        }

        /// <summary>
        /// 深さ優先探索
        /// </summary>
        /// <param name="x">開始点index</param>
        /// 隣接行列graph[点数][点数], 到達チェックvisited[点数]が存在するとする
        public static void DFS(int x)
        {
            if(visitedPoints[x] == true)//一度見たらもう見なくてもいいので戻る
            {
                return;
            }
            visitedPoints[x] = true;//到達したのでチェック
            //次に行ける点を探索。次に行ける点=点Xからつながっている点
            for (int i = 0; i < NUM_POINT; ++i)
            {
                if(graph[x,i] == true)//点Xから接続されている辺を見ている
                {
                    DFS(i);//i番目の点が接続されていた。そこからDFSする
                }
            }
        }

    }
}