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<math.h>
#include<string.h>
#include <time.h>
typedef long long llint;
typedef long double ldouble;
// 小大
int compare(const void *a, const void *b){return *(llint *)a - *(llint *)b;}
typedef struct{
    llint aa;
    llint bb;
}frequent;
// 小大
int cmp( const void *p, const void *q ) {
    return ((frequent*)p)->bb - ((frequent*)q)->bb;
}
llint memoplace[50];
llint route(llint n, llint gra[n][n], llint bra[], llint a1, llint a, llint b){
    // printf("?%lld %lld? ",a,b);
    if(memoplace[a-1] == 1){
        // printf(" c ");
        return 0;
    }
    llint ans=0;
    memoplace[a-1] = 1;
    // printf(" /%lld/ ",bra[a-1]);
    for(llint i=0;i<bra[a-1];i++){
        // printf("|%lld,%lld,%lld|",gra[a-1][i],a-1,i);
        if(gra[a-1][i] == b && a1==a){
            // printf(" q ");
            continue;
        }
        if(gra[a-1][i] == b) return 1;
        ans = route(n,gra,bra,a1,gra[a-1][i],b);
        if(ans!=0) return 1;
    }
    // printf(" r ");
    return 0;
}


int main(void){
    llint n,m,i,ans=0;
    scanf("%lld%lld",&n,&m);
    llint a[m],b[m],graph[n][n],branch[n];
    for(i=0;i<n;i++){
        branch[i]=0;
        for(llint j=0;j<n;j++){
            graph[i][j]=0;
        }    
    }
    for(i=0;i<m;i++){
        scanf("%lld%lld",&a[i],&b[i]);
        branch[a[i]-1]++;
        branch[b[i]-1]++;
        graph[a[i]-1][branch[a[i]-1]-1] = b[i];
        graph[b[i]-1][branch[b[i]-1]-1] = a[i];
    }

    // for(i=0;i<n;i++){
    //     for(llint j=0;j<n;j++){
    //         printf("%lld ",graph[i][j]);
    //     }
    //     printf("\n");
    // }

    // ans = route(n,graph,branch,a[3],a[3],b[3]);

    for(i=0;i<m;i++){
        for(llint j=0;j<n;j++){
            memoplace[j] = 0;
        }
        // printf("%lld\n",route(n,graph,branch,a[i],a[i],b[i]));
        // for(llint j=0;j<n;j++){
        //     printf("%lld ",memoplace[j]);
        // }
        // printf("\n");
        if( route(n,graph,branch,a[i],a[i],b[i]) == 0) ans++;
        
    }

    // printf("\n");
    printf("%lld\n",ans);
    return 0;
}
*/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include <time.h>
typedef long long llint;
typedef long double ldouble;
/*swap 交換*/
void swap(llint *a, llint *b){llint c;c=*b;*b=*a;*a=c;}
/*2つのうち大きい数を返す*/
llint max2(llint a,llint b){return a>=b?a:b;}
/*2つのうち小さい数を返す*/
llint min2(llint a,llint b){return a>=b?b:a;}

typedef struct{
    llint num; //number
    llint par; //parent
    llint height; //height
}UF;

void UFmake(llint n, UF b[n]){for(llint i=0;i<n;i++){
    b[i].par = i+1;
    b[i].num = i+1;
    b[i].height = 1;}}

llint UFroot(llint n, llint a,UF b[n]){
    return a==b[a-1].par?a:UFroot(n,b[a-1].par,b);}
    
void UFunite(llint n, llint x, llint y, UF b[n]){
    if(b[UFroot(n,x,b)-1].height > b[UFroot(n,y,b)-1].height){
        b[UFroot(n,y,b)-1].par = UFroot(n,x,b);
    }else{
        b[UFroot(n,x,b)-1].par = UFroot(n,y,b);
        b[UFroot(n,y,b)-1].height = max2(b[UFroot(n,y,b)-1].height,b[UFroot(n,x,b)-1].height+1);
    }
}

llint UFsame(llint n, llint x, llint y, UF b[n]){
    if( UFroot(n,x,b) == UFroot(n,y,b) ){
        return 1;
    }
    return 0;
}


int main(void){
    llint n,m,i,ans=0;
    scanf("%lld%lld",&n,&m);
    llint a[m],b[m];
    UF tree[n];
    for(i=0;i<m;i++){
        scanf("%lld%lld",&a[i],&b[i]);
    }
    for(i=0;i<m;i++){
        UFmake(n,tree);
        for(llint j=0;j<m;j++){
            if(i==j) continue;
            UFunite(n,a[j],b[j],tree);
        }
        if( ! UFsame(n,a[i],b[i],tree) ) ans++;
    }
    printf("%lld\n",ans);
    return 0;
}