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 (GCC 5.4.1) (judge verdict: Accepted)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define NEW(p,n){p=malloc((n)*sizeof(p[0]));if(p==NULL){printf("not enough memory\n");exit(1);};}
//pの型の変数n個の要素分のメモリを確保し、そのアドレスをpに代入するマクロ

#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define SWAP(type, x, y) do { type tmp = x; x = y; y = tmp; } while (0)

#define MOD 1000000007 

typedef struct slobj_{
    struct slobj_ *next;
    int v; //uから枝が伸びている節点v
    long d; //枝(u,v)の重み
}* slobj;

//slobj型のリストの定義
typedef struct{
    slobj head;
    slobj tail;
}* slist;

//グラフの構造体の定義
typedef struct{
    int n; //節点数
    slist* E; //枝リストの配列E[0]~E[n-1],未ソート単方向
}* graph;

//vにn,dにxを持つslobj型のリスト要素のメモリ確保+作成する関数
slobj slobj_new(int n,long x){
    slobj p;
    NEW(p,1);
    p->v=n;
    p->d=x;
    p->next=NULL;
    return p;
}

//slist型のメモリを1個確保し、空リスト1つを作る関数
slist slist_new(void){
    slist L;
    NEW(L,1);
    L->head=NULL;
    L->tail=NULL;
    return L;
}

//各slistを空リストにした,節点nのgraph型のメモリを確保する関数(Eは0カウント)
graph graph_new(int n){
    graph G;
    NEW(G,1);
    
    G->n=n;
    
    NEW(G->E,G->n);
    int i;
    for(i=0;i<G->n;i++){
        G->E[i]=slist_new();
    }
    
    return G;
}

//リストLの末尾に要素rを追加する関数
void slist_append_tail(slist L,slobj r){
    if(L->head==NULL){
        L->head=r;
        L->tail=r;
    }
    else{
        L->tail->next=r;
        L->tail=r;
    }
    
    return;
}

//節点i(0~n-1)から節点j(0~n-1)に、重さxの枝を追加する関数
void add_edge(graph G, int i, int j, int x){
    //枝データを追加
    slobj p=slobj_new(j,x);
    slist_append_tail(G->E[i],p);

    return;
}

void delete_edge(graph G, int i, int j){
    slobj p=G->E[i]->head;
    slobj q=NULL;
    while(p!=NULL){
        if(p->v==j) break;
        q=p;
        p=p->next;
    }
    //削除するpがhead
    if(q==NULL){
        G->E[i]->head=p->next;
    }
    else{
        q->next=p->next;
    }
    //削除するpがtail
    if(p->next==NULL){
        G->E[i]->tail=q;
    }
    return;
}

//根(節点i)からの長さをdfs
void dfs(graph G, int i, int* d){
	slobj p=G->E[i]->head;
	while(p!=NULL){
		if(d[p->v]==-1){ //未探索なら
			d[p->v]=d[i]+p->d;
			dfs(G,p->v,d);
		}
		p=p->next;
	}
	return;
}

typedef struct{
    int a;
    int b;
}edge;

int main(void){
    int N,M;
    scanf("%d%d",&N,&M);

    graph G=graph_new(N);
    edge* A;
    NEW(A,M);

    for(int i=0;i<M;i++){
        scanf("%d%d",&A[i].a,&A[i].b);
        A[i].a--;
        A[i].b--;
        add_edge(G,A[i].a,A[i].b,1);
        add_edge(G,A[i].b,A[i].a,1);
    }

    int ans=0;
    for(int i=0;i<M;i++){
        delete_edge(G,A[i].a,A[i].b);
        delete_edge(G,A[i].b,A[i].a);

        int d[N];
        for(int j=0;j<N;j++) d[j]=-1;

        d[0]=0;
        dfs(G,0,d);

        for(int j=0;j<N;j++){
            if(d[j]==-1){
                ans++;
                break;
            }
        }

        add_edge(G,A[i].a,A[i].b,1);
        add_edge(G,A[i].b,A[i].a,1);
    }
    printf("%d\n",ans);

    return 0;
}