RT
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#include <climits>
#include <queue>
#include <stack>
#define endl "\n"
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define int long long
#define ULL unsigned long long
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define mid(a, b) (a + b) >> 1
const int N = 5e3 + 6, M = 1e4 + 5;
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
int n, m;
int h[N], edges;
struct node
{
int nx, to;
}e[M * 2];
int st[N], top, low[N], num[N], dfn, res, ans;
int u[N], v[N], color[N], degree[N];
bool vis[M * 2], insta[N];
void add(int u, int v)
{
edges ++;
e[edges].nx = h[u], e[edges].to = v, h[u] = edges;
edges ++;
e[edges].nx = h[v], e[edges].to = u, h[v] = edges;
}
void tarjan(int u)
{
low[u] = num[u] = ++ dfn;
st[++ top] = u, insta[u] = true;
for (int i = h[u]; i; i = e[i].nx)
{
if (vis[i]) continue;
vis[i] = vis[i ^ 1] = true;
int j = e[i].to;
if (!num[j]) tarjan(j), low[u] = min(low[u], low[j]);
else if (insta[j]) low[u] = min(low[u], num[j]);
}
if (num[u] == low[u])
{
color[u] = ++ res;
insta[u] = false;
while (st[top] != u) color[st[top]] = res, insta[st[top]] = false, top --;
top --;
}
}
signed main()
{
//IOS;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++ )
{
scanf("%d%d", &u[i], &v[i]);
add(u[i], v[i]);
}
for (int i = 1; i <= n; i ++ )
{
if (!num[i]) tarjan(i);
}
for (int i = 1; i <= m; i ++ )
{
if (color[u[i]] != color[v[i]]) degree[color[u[i]]] ++, degree[color[v[i]]] ++;
}
for (int i = 1; i <= res; i ++ )
if (degree[i] == 1) ans ++;
//cout << ans << endl;
printf("%d", (ans + 1) / 2);
}