#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <ctime>
#include <set>
#include <map>

#define X first
#define Y second
#define pb push_back

using namespace std;

typedef long long lint;
typedef pair<int, int> pii;
typedef set<int> Si;
typedef vector<int> Vi;
typedef vector<int> :: iterator Vi_it;
typedef set<int> :: iterator Si_it;

const double eps = 1e-9;
const double PI = acos(-1.0);

inline int dcmp(const double & x)
{return x < -eps ? -1 : x > eps;}
const int Mn = 2000 + 10, Me = 100000 * 2 + 10;
int hd[Mn],nxt[Me],to[Me],cnt;
int hd1[Mn],nxt1[Me],to1[Me],cnt1;
int dfn[Mn],low[Mn],stack[Mn],scc[Mn],sc,top,tot;
int size_sc[Mn],size[Mn];
int vis[Mn],num;
int n,m;
inline void add(int x,int y)
{
	to[cnt] = y;
	nxt[cnt] = hd[x];
	hd[x] = cnt++;
}
inline void add1(int x,int y)
{
	to1[cnt1] = y;
	nxt1[cnt1] = hd1[x];
	hd1[x] = cnt1++;
}
inline void tarjan(int x,int p)
{
	stack[++top] = x;
	dfn[x] = low[x] = ++tot;
	for(int i = hd[x]; ~i; i = nxt[i])
		if(i != p)
		{
			if(!dfn[to[i]])
				tarjan(to[i],i^1);
			low[x] = min(low[x],low[to[i]]);
		}
	if(low[x] == dfn[x])
	{
		int now;
		sc++;
		//printf("%d : ",sc);
		do
		{
			now = stack[top--];
			//printf(" %d",now);
			scc[now] = sc;
			size_sc[sc]++;
		}while(now != x);
		//puts("");
	}
}
inline void dfs(int x,int p)
{
	vis[x] = num;
	for(int i = hd1[x]; ~i; i = nxt1[i])
		if(i != p)
			dfs(to1[i],i^1);
}
inline void get_size(int x,int p)
{
	size[x] = 1;
	for(int i = hd1[x]; ~i; i = nxt1[i])
		if(i != p)
		{
			get_size(to1[i],i^1);
			size[x] += size[to1[i]];
		}
}
inline int dp(int x,int p)
{
	int res(0x7fffffff);
	int tot(0);
	for(int i = hd1[x]; ~i; i = nxt1[i])
		if(i != p)
			tot++;
	if(!tot)
		return 0;
	for(int i = hd1[x]; ~i; i = nxt1[i])
		if(i != p)
			res = min(res,dp(to1[i],i^1)+size[x]-size[to1[i]]-tot);
	return res;
}
inline int solve(int x)
{
	dfs(x,-1);
	int res(0x7fffffff);
	for(int i = 1; i <= sc; i++)
		if(vis[i] == num)
		{
			get_size(i,-1);
			res = min(res,dp(i,-1));
		}
	return res;
}
int main()
{
	memset(hd,-1,sizeof hd);
	memset(hd1,-1,sizeof hd1);
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= m; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	for(int i = 1; i <= n; i++)
		if(!dfn[i])
			tarjan(i,-1);
	int ans(0);
	for(int i = 1; i <= sc; i++)
		ans += size_sc[i] - 1;
	for(int i = 1; i <= n; i++)
		for(int j = hd[i]; ~j; j = nxt[j])
			if(scc[i] < scc[to[j]])
			{
				//printf("%d - %d\n",scc[i],scc[to[j]]);
				add1(scc[i],scc[to[j]]);
				add1(scc[to[j]],scc[i]);
			}
	for(int i = 1; i <= sc; i++)
		if(!vis[i])
		{
			num++;
			ans += solve(i);
		}
	cout << ans + num - 1 << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <vector>
#include <set>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <bitset>
#include <queue>
#include <sstream>

using namespace std;

#define mp make_pair
#define pb push_back
#define rep(i,n) for(int i = 0; i < n; i++)
#define re return
#define fi first
#define se second
#define sz(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define y0 y3487465
#define y1 y8687969

typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<string> vs;
typedef vector<vi> vvi;

template<class T> T abs(T x) {
	re x > 0 ? x : -x;
}

int n;
int m, r = 0, t;
int was[2000], cmp[2000], cnt[2000], res[2000], e[2000], leaf[2000];
int g[2000][2000], w[2000][2000];
vi v[2000], vv[2000];
vi q;

int go (int x) {
	was[x] = 1;
	for (int i = 0; i < sz (v[x]); i++) {
		int y = v[x][i];
		if (!was[y]) {
			g[x][y] = 2;
			go (y);
		}
	}
	q.pb (x);
	re 0;
}

int go2 (int x, int k) {
	was[x] = 1;
	cmp[x] = k;
	for (int i = 0; i < sz (v[x]); i++) {
		int y = v[x][i];
		if (!was[y] && g[x][y] == 1) go2 (y, k);
	}
	re 0;
}

int go3 (int x, int p) {
	int il = 1;
	leaf[x] = 0;
	cnt[x] = 1;
	for (int i = 0; i < sz (vv[x]); i++) {
		int y = vv[x][i];
		if (y != p) {
			go3 (y, x);
			cnt[x] += cnt[y];
			leaf[x] += leaf[y];
			il = 0;
		}
	}
	leaf[x] += il;
	int cur = cnt[x] - leaf[x];
	for (int i = 0; i < sz (vv[x]); i++) {
		int y = vv[x][i];
		if (y != p) {
			int tmp = res[y] + (cnt[x] - leaf[x]) - (cnt[y] - leaf[y]) - 1;
			cur = min (cur, tmp);
		}
	}
	res[x] = cur;
	re cur;
}

int go4 (int x, int p) {
	was[x] = 1;
	for (int i = 0; i < sz (vv[x]); i++) {
		int y = vv[x][i];
		if (y != p) go4 (y, x);
	}
	if (sz (vv[x]) < 2) e[t++] = x;
	re 0;
}

int main() {
	scanf ("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		int a, b;
		scanf ("%d%d", &a, &b); a--; b--;
		v[a].pb (b);
		v[b].pb (a);
		g[a][b] = g[b][a] = 1;
	}
	memset (was, 0, sizeof (was));
	for (int i = 0; i < n; i++)
		if (!was[i])
			go (i);
	memset (was, 0, sizeof (was));
	reverse (all (q));
	for (int i = 0; i < n; i++)
		if (!was[q[i]]) {
			go2 (q[i], r);
			r++;
		}
	for (int i = 0; i < n; i++)
		for (int j = i + 1; j < n; j++)
			if (cmp[i] != cmp[j] && g[i][j] && !w[cmp[i]][cmp[j]]) {
				vv[cmp[i]].pb (cmp[j]);
				vv[cmp[j]].pb (cmp[i]);
				w[cmp[i]][cmp[j]] = w[cmp[j]][cmp[i]] = 1;
			}
	int ans = n - r;
	memset (was, 0, sizeof (was));
	for (int i = 0; i < r; i++)
		if (!was[i]) {
			t = 0;
			go4 (i, i);
			int tmp = n;
			for (int j = 0; j < t; j++) {
				int tmp2 = go3 (e[j], e[j]);
				tmp = min (tmp, tmp2);
			}
			ans += tmp + 1;
		}
	printf ("%d\n", ans - 1);
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 4001,maxm = 200001,oo = ~0U >> 1;

typedef int d1[maxn];
typedef int d2[maxm];

int n,m,times,top,num,tot,ans;
d1 head,d,vis,siz,s,dfn,low,team,have;
d2 e,next,used,u,v;

void add(int i,int j)
{
    e[++tot] = j,next[tot] = head[i],head[i] = tot;
}

void dfs(int x)
{
    vis[x] = true;
    siz[x] = 1;
    for (int p = head[x]; p; p = next[p])
        if (!vis[e[p]]) d[e[p]] = d[x]+1,dfs(e[p]),siz[x] = siz[x]+siz[e[p]];
}

void work(int x)
{
    memset(d,0,sizeof(d));
    memset(vis,0,sizeof(vis));
    memset(siz,0,sizeof(siz));
    dfs(x);
}

int tarjan(int x)
{
    if (dfn[x]) return low[x];
    dfn[x] = low[x] = ++times;
    s[++top] = x;
    for (int p = head[x]; p; p = next[p])
        if (!used[p])
        {
            used[p ^ 1] = true;
            low[x] = min(low[x],tarjan(e[p]));
            used[p ^ 1] = false;
        }
    int tmp = low[x];
    if (dfn[x] == low[x])
    {
        ++num;
        for (; s[top+1] != x; --top)
        {
            team[s[top]] = num;
            dfn[s[top]] = low[s[top]] = oo;
        }
    }
    return tmp;
}

int main()
{
    int i,j,k;
    int root;

    tot = 1;
    scanf("%d%d",&n,&m);
    for (i = 1; i <= m; ++i)
        scanf("%d%d",&u[i],&v[i]),add(u[i],v[i]),add(v[i],u[i]);
    ans = n-1;
    for (root = 1; root <= n; ++root)
        if (!have[root])
        {
            work(root);
            for (i = 1; i <= n; ++i)
                have[i] |= vis[i];
            tarjan(root);
            ++ans;
        }
    memset(head,0,sizeof(head));
    memset(e,0,sizeof(e));
    memset(next,0,sizeof(next));
    tot = 1;
    for (i = 1; i <= m; ++i)
        if (team[u[i]] != team[v[i]]) add(team[u[i]],team[v[i]]),add(team[v[i]],team[u[i]]);

    memset(have,0,sizeof(have));
    for (root = 1; root <= num; ++root)
        if (!have[root])
        {
            work(root);
            for (i = 1; i <= num; ++i)
                have[i] |= vis[i];
            for (i = 1,j = root; i <= num; ++i)
                if (d[i] > d[j] && vis[i]) j = i;
            work(j);
            for (i = 1,k = root; i <= num; ++i)
                if (d[i] > d[k] && vis[i]) k = i;

            for (i = 1; i <= num; ++i)
                if (siz[i] == 1) --ans;
            ans -= d[k];
        }
    printf("%d",ans);

    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 4001,maxm = 200001,oo = ~0U >> 1;

typedef int d1[maxn];
typedef int d2[maxm];

int n,m,times,top,num,tot,ans;
d1 head,d,vis,siz,s,dfn,low,team,have;
d2 e,next,used,u,v;

void add(int i,int j)
{
    e[++tot] = j,next[tot] = head[i],head[i] = tot;
}

void dfs(int x)
{
    vis[x] = true;
    siz[x] = 1;
    for (int p = head[x]; p; p = next[p])
        if (!vis[e[p]]) d[e[p]] = d[x]+1,dfs(e[p]),siz[x] = siz[x]+siz[e[p]];
}

void work(int x)
{
    memset(d,0,sizeof(d));
    memset(vis,0,sizeof(vis));
    memset(siz,0,sizeof(siz));
    dfs(x);
}

int tarjan(int x)
{
    if (dfn[x]) return low[x];
    dfn[x] = low[x] = ++times;
    s[++top] = x;
    for (int p = head[x]; p; p = next[p])
        if (!used[p])
        {
            used[p ^ 1] = true;
            low[x] = min(low[x],tarjan(e[p]));
            used[p ^ 1] = false;
        }
    int tmp = low[x];
    if (dfn[x] == low[x])
    {
        ++num;
        for (; s[top+1] != x; --top)
        {
            team[s[top]] = num;
            dfn[s[top]] = low[s[top]] = oo;
        }
    }
    return tmp;
}

int main()
{
    int i,j,k;
    int root;

    tot = 1;
    scanf("%d%d",&n,&m);
    for (i = 1; i <= m; ++i)
        scanf("%d%d",&u[i],&v[i]),add(u[i],v[i]),add(v[i],u[i]);
    ans = n-1;
    for (root = 1; root <= n; ++root)
        if (!have[root])
        {
            work(root);
            for (i = 1; i <= n; ++i)
                have[i] |= vis[i];
            tarjan(root);
            ++ans;
        }
    memset(head,0,sizeof(head));
    memset(e,0,sizeof(e));
    memset(next,0,sizeof(next));
    tot = 1;
    for (i = 1; i <= m; ++i)
        if (team[u[i]] != team[v[i]]) add(team[u[i]],team[v[i]]),add(team[v[i]],team[u[i]]);

    memset(have,0,sizeof(have));
    for (root = 1; root <= num; ++root)
        if (!have[root])
        {
            work(root);
            for (i = 1; i <= num; ++i)
                have[i] |= vis[i];
            for (i = j = 1; i <= num; ++i)
                if (d[i] > d[j]) j = i;
            work(j);
            for (i = k = 1; i <= num; ++i)
                if (d[i] > d[k]) k = i;
            for (i = 1; i <= num; ++i)
                if (siz[i] == 1) --ans;
            ans -= d[k];
        }
    printf("%d",ans);

    return 0;
}


#include<cstdio>
#include<algorithm>
using namespace std;
#define For(i,x,y) for(int i=(int)x,_y=y;i<=_y;i++)
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0',c=getchar());
	return f?-x:x;
}
const int N=2000+10;
struct edge{int to,nxt;}e[200005],E[N*2];
int n,m,cnt,dfs_clock,leaf,s,len,scc_cnt,Head[N],head[N],sta[N],dfn[N],low[N],belong[N],d[N];
bool vis[N];
void addedge(int u,int v)
{
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void tarjan(int u,int fa)
{
	sta[++*sta]=u;dfn[u]=low[u]=++dfs_clock;
	for(int i=head[u],v;i;i=e[i].nxt)if((v=e[i].to)!=fa)
	{
		if(!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
			else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
		for(++scc_cnt;;)
		{
			int x=sta[*sta];
			--*sta;
			belong[x]=scc_cnt;
			if(x==u)break;
		}
}
void Addedge(int u,int v)
{
	E[++cnt]=(edge){v,Head[u]};Head[u]=cnt;
	E[++cnt]=(edge){u,Head[v]};Head[v]=cnt;
	d[u]++;d[v]++;
}
void dfs(int u,int fa,int dis)
{
	vis[u]=1;if(d[u]<=1)leaf++;
	if(dis>len)len=dis,s=u;
	for(int i=Head[u],v;i;i=E[i].nxt)if((v=E[i].to)!=fa)dfs(v,u,dis+1);
}
int main()
{
	n=read(),m=read();
	For(i,1,m)addedge(read(),read());
	For(i,1,n)if(!dfn[i])tarjan(i,0);cnt=0;
	For(u,1,n)for(int i=head[u],v;i;i=e[i].nxt)if(belong[u]<belong[v=e[i].to])Addedge(belong[u],belong[v]);
	For(i,1,scc_cnt)if(!vis[i])
	{
		n++;
		leaf=s=len=0;dfs(i,0,1);
		leaf=len=0;dfs(s,0,1);
		if(len==1&&leaf==1)n--;else n-=len+leaf-2;
	}
	printf("%d\n",n-1);
}


#include<cstdio>
#include<algorithm>
using namespace std;
#define For(i,x,y) for(int i=(int)x,_y=y;i<=_y;i++)
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0',c=getchar());
	return f?-x:x;
}
const int N=2000+10;
struct edge{int to,nxt;}e[200005],E[N*2];
int n,m,cnt,dfs_clock,leaf,s,len,scc_cnt,Head[N],head[N],sta[N],dfn[N],low[N],belong[N],d[N];
bool vis[N];
void addedge(int u,int v)
{
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void tarjan(int u,int fa)
{
	sta[++*sta]=u;dfn[u]=low[u]=++dfs_clock;
	for(int i=head[u],v;i;i=e[i].nxt)if((v=e[i].to)!=fa)
	{
		if(!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
			else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
		for(++scc_cnt;;)
		{
			int x=sta[*sta];
			--*sta;
			belong[x]=scc_cnt;
			if(x==u)break;
		}
}
void Addedge(int u,int v)
{
	E[++cnt]=(edge){v,Head[u]};Head[u]=cnt;
	E[++cnt]=(edge){u,Head[v]};Head[v]=cnt;
	d[u]++;d[v]++;
}
void dfs(int u,int fa,int dis)
{
	vis[u]=1;if(d[u]==1)leaf++;
	if(dis>len)len=dis,s=u;
	for(int i=Head[u],v;i;i=E[i].nxt)if((v=E[i].to)!=fa)dfs(v,u,dis+1);
}
int main()
{
	n=read(),m=read();
	For(i,1,m)addedge(read(),read());
	For(i,1,n)if(!dfn[i])tarjan(i,0);cnt=0;
	For(u,1,n)for(int i=head[u],v;i;i=e[i].nxt)if(belong[u]<belong[v=e[i].to])Addedge(belong[u],belong[v]);
	For(i,1,scc_cnt)if(!vis[i])
	{
		n++;
		leaf=s=len=0;dfs(i,0,1);
		leaf=len=0;dfs(s,0,1);
		if(len==1&&leaf==1)n--;else n-=len+leaf-2;
	}
	printf("%d\n",n-1);
}


#include<cstdio>
#include<algorithm>
using namespace std;
#define For(i,x,y) for(int i=(int)x,_y=y;i<=_y;i++)
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0',c=getchar());
	return f?-x:x;
}
const int N=2000+10;
struct edge{int to,nxt;}e[200005],E[N*2];
int n,m,cnt,dfs_clock,leaf,s,len,scc_cnt,Head[N],head[N],sta[N],dfn[N],low[N],belong[N],d[N];
bool vis[N];
void addedge(int u,int v)
{
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void tarjan(int u,int fa)
{
	sta[++*sta]=u;dfn[u]=low[u]=++dfs_clock;
	for(int i=head[u],v;i;i=e[i].nxt)if((v=e[i].to)!=fa)
	{
		if(!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
			else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
		for(++scc_cnt;;)
		{
			int x=sta[*sta];
			--*sta;
			belong[x]=scc_cnt;
			if(x==u)break;
		}
}
void Addedge(int u,int v)
{
	E[++cnt]=(edge){v,Head[u]};Head[u]=cnt;
	E[++cnt]=(edge){u,Head[v]};Head[v]=cnt;
	d[u]++;d[v]++;
}
void dfs(int u,int fa,int dis)
{
	vis[u]=1;if(d[u]<1)leaf++;
	if(dis>len)len=dis,s=u;
	for(int i=Head[u],v;i;i=E[i].nxt)if((v=E[i].to)!=fa)dfs(v,u,dis+1);
}
int main()
{
	n=read(),m=read();
	For(i,1,m)addedge(read(),read());
	For(i,1,n)if(!dfn[i])tarjan(i,0);cnt=0;
	For(u,1,n)for(int i=head[u],v;i;i=e[i].nxt)if(belong[u]<belong[v=e[i].to])Addedge(belong[u],belong[v]);
	For(i,1,scc_cnt)if(!vis[i])
	{
		n++;
		leaf=s=len=0;dfs(i,0,1);
		leaf=len=0;dfs(s,0,1);
		if(len==1&&leaf==1)n--;else n-=len+leaf-2;
	}
	printf("%d\n",n-1);
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2100
#define M 101000
using namespace std;
int n,m;
int head[N];
int cnt;
int fa[N];
int find(int x)
{
    if(x==fa[x])return fa[x];
    return fa[x]=find(fa[x]);
}
struct Line
{
    int u,v;
}L[M];
struct node
{
    int from,to,next;
}edge[M<<1];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(int from,int to)
{
    edge[cnt].from=from,edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
int deep[N],low[N],ins[N],sta[N];
int tot,top,cnt_block;
int belong[N];
void tarjan(int now,int ff)
{
    deep[now]=low[now]=++tot;
    ins[now]=1,sta[++top]=now;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==ff)continue;
        if(!deep[to])
        {
            tarjan(to,now);
            low[now]=min(low[now],low[to]);
        }else if(ins[to])low[now]=min(low[now],deep[to]);
    }
    if(deep[now]==low[now])
    {
        int t=-1;
        cnt_block++;
        do
        {
            t=sta[top--];
            ins[t]=0;
            belong[t]=cnt_block;
        }while(t!=now);
    }
}
int du[N];
int dec[N],siz[N];
int maxchain[N];
int depth;
void dfs(int now,int ff)
{
    deep[now]=tot;
    siz[tot]++;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==ff)continue;
        dfs(to,now);
    }
}
void dfs2(int now,int dep,int ff)
{
    depth=max(depth,dep);
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==ff||du[to]==1)continue;
        dfs2(to,dep+1,now);
    }
}
int ans;
int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        edgeadd(x,y);
        edgeadd(y,x);
        L[i].u=x,L[i].v=y;
    }
    for(int i=1;i<=n;i++)
    {
        if(!deep[i])
            tarjan(i,0);
    }
    ans=n-cnt_block;
    init();
    for(int i=1;i<=cnt_block;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x=belong[L[i].u],y=belong[L[i].v];
        int fx=find(x),fy=find(y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            edgeadd(x,y);
            edgeadd(y,x);
            du[x]++;
            du[y]++;
        }
    }
    memset(deep,0,sizeof(deep));tot=0;
    for(int i=1;i<=cnt_block;i++)
    {
        if(!deep[i])
        {
            tot++;
            dfs(i,0);
        }
    }
    for(int i=1;i<=cnt_block;i++)
    {
        if(du[i]==1)siz[deep[i]]--;
        else
        {
            depth=0;
            dfs2(i,1,0);
            maxchain[deep[i]]=max(maxchain[deep[i]],depth);
        }
    }
    for(int i=1;i<=tot;i++)
    {
        ans+=siz[i]-maxchain[i];
    }
    printf("%d\n",ans+tot-1);
}


#include<cstdio>
#include<algorithm>
#define For(i,n) for(int i=1;i<=n;i++)
#define N 2010
#define M 200010
using namespace std;
int n,m,u,v,bcc;

struct Graph
{
	int sz,top,tot,time,sk[N],cr[N],en[N],low[N],dfn[N],pre[M],g[M];
	Graph() { sz=1;top=tot=0; }
	void Ins(int u,int v)
	{
		pre[++sz]=en[u];en[u]=sz;g[sz]=v;
	}
	void Popto(int x)
	{
		tot++;
		for(;sk[top+1]!=x;top--)
		    cr[sk[top]]=tot;
	}
	void Tarjan(int x,int way)
	{
		dfn[x]=low[x]=++time;
		sk[++top]=x;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];
			if (!dfn[v])
			{
				Tarjan(v,i^1);
				low[x]=min(low[x],low[v]);
			}
			else if (i!=way) low[x]=min(low[x],dfn[v]);
		}
		if (low[x]==dfn[x]) Popto(x);
	}
	int bcc()
	{
		For(i,n) if(!dfn[i]) Tarjan(i,0);
		return tot;
	}
}G;
struct Tree:Graph
{
	int Max,leaf,f[N];
	void dfs(int x,int fa)
	{
		int p=0,q=0,ch=0;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];ch++;
			if (v==fa) continue;
			dfs(v,x);
			if (f[v]>p) {q=p;p=f[v];}
			else if (f[v]>q) q=f[v];
		}
		if (ch==1) leaf++;
		f[x]=p+1;
		Max=max(Max,p+q+1);
	}
	int Calc(int n)
	{
		tot=1;
		For(x,n)
			if (!f[x])
			{
				Max=leaf=0;
				dfs(x,0);
				tot+=Max+leaf-2-1;
			}
		return tot;
	}
}T;
int main()
{
	scanf("%d%d",&n,&m);
	For(i,m)
	{
		scanf("%d%d",&u,&v);
		G.Ins(u,v);G.Ins(v,u);
	}
	G.bcc();
	For(x,n)
	    for(int i=G.en[x];i;i=G.pre[i])
	    {
			int v=G.g[i];
			if (G.cr[x]!=G.cr[v])
				T.Ins(G.cr[x],G.cr[v]);
		}
	printf("%d\n",n-T.Calc(G.tot));
	return 0;
}


#include<cstdio>
#include<algorithm>
#define For(i,n) for(int i=1;i<=n;i++)
#define N 2010
#define M 200010
using namespace std;
int n,m,u,v,bcc;

struct Graph
{
	int sz,top,tot,time,sk[N],cr[N],en[N],low[N],dfn[N],pre[M],g[M];
	Graph() { sz=1;top=tot=0; }
	void Ins(int u,int v)
	{
		pre[++sz]=en[u];en[u]=sz;g[sz]=v;
	}
	void Popto(int x)
	{
		tot++;
		for(;sk[top+1]!=x;top--)
		    cr[sk[top]]=tot;
	}
	void Tarjan(int x,int way)
	{
		dfn[x]=low[x]=++time;
		sk[++top]=x;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];
			if (!dfn[v])
			{
				Tarjan(v,i^1);
				low[x]=min(low[x],low[v]);
			}
			else if (i!=way) low[x]=min(low[x],dfn[v]);
		}
		if (low[x]==dfn[x]) Popto(x);
	}
	int bcc()
	{
		For(i,n) if(!dfn[i]) Tarjan(i,0);
		return tot;
	}
}G;
struct Tree:Graph
{
	int Max,leaf,sum,f[N];
	void dfs(int x,int fa)
	{
		int p=0,q=0,ch=0;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];ch++;
			if (v==fa) continue;
			dfs(v,x);
			if (f[v]>p) {q=p;p=f[v];}
			else if (f[v]>q) q=f[v];
		}
		if (ch==1) leaf++;
		f[x]=p+1;
		Max=max(Max,p+q+1);
	}
	int Calc(int n)
	{
		tot=1;
		For(x,n)
			if (!f[x])
			{
				Max=leaf=0;
				dfs(x,0);
				if (leaf>1) tot+=Max+leaf-2-1;
			}
		return tot;
	}
}T;
int main()
{
	scanf("%d%d",&n,&m);
	For(i,m)
	{
		scanf("%d%d",&u,&v);
		G.Ins(u,v);G.Ins(v,u);
	}
	G.bcc();
	For(x,n)
	    for(int i=G.en[x];i;i=G.pre[i])
	    {
			int v=G.g[i];
			if (G.cr[x]!=G.cr[v])
				T.Ins(G.cr[x],G.cr[v]);

		}
	printf("%d\n",n-T.Calc(G.tot));
	return 0;
}


#include<cstdio>
#include<algorithm>
#define For(i,n) for(int i=1;i<=n;i++)
#define N 2010
#define M 200010
using namespace std;
int n,m,u,v,bcc;

struct Graph
{
	int sz,top,tot,time,sk[N],cr[N],en[N],low[N],dfn[N],pre[M],g[M];
	Graph() { sz=1;top=tot=0; }
	void Ins(int u,int v)
	{
		pre[++sz]=en[u];en[u]=sz;g[sz]=v;
	}
	void Popto(int x)
	{
		tot++;
		for(;sk[top+1]!=x;top--)
		    cr[sk[top]]=tot;
	}
	void Tarjan(int x,int way)
	{
		dfn[x]=low[x]=++time;
		sk[++top]=x;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];
			if (!dfn[v])
			{
				Tarjan(v,i^1);
				low[x]=min(low[x],low[v]);
			}
			else if (i!=way) low[x]=min(low[x],dfn[v]);
		}
		if (low[x]==dfn[x]) Popto(x);
	}
	int bcc()
	{
		For(i,n) if(!dfn[i]) Tarjan(i,0);
		return tot;
	}
}G;
struct Tree:Graph
{
	int MMC,f[N];
	void dfs(int x,int fa)
	{
		int p=1,q=1,ch=0;
		for(int i=en[x];i;i=pre[i])
		{
			int v=g[i];
			if (v==fa) continue;
			ch++;
			dfs(v,x);
			if (f[v]>p) {q=p;p=f[v];}
			else if (f[v]>q) q=f[v];
		}
		f[x]=p+ch;
		MMC=max(MMC,p+q+1+ch+(fa>0)-2);
	}
	int Calc(int n)
	{
		tot=1;
		For(x,n)
			if (!f[x])
			{
				MMC=0;
				dfs(x,0);
				tot+=MMC-1;
			}
		return tot;
	}
}T;
int main()
{
	//freopen("CF-51-E.in","r",stdin);
	scanf("%d%d",&n,&m);
	For(i,m)
	{
		scanf("%d%d",&u,&v);
		G.Ins(u,v);G.Ins(v,u);
	}
	G.bcc();
	For(x,n)
	    for(int i=G.en[x];i;i=G.pre[i])
	    {
			int v=G.g[i];
			if (G.cr[x]!=G.cr[v])
				T.Ins(G.cr[x],G.cr[v]);
		}
	printf("%d\n",n-T.Calc(G.tot));
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
using namespace std;

typedef long long int LL;
const int MAXN = 5000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;

template<class T>
void Read(T &x){
    x=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(flag)x=-x;
}

struct node{
    int v;
    node *nxt;
}*adj[MAXN+10],Edges[MAXM*2+10],*New;
void init(){memset(adj,0,sizeof(adj));New=Edges;}
void addedges(int u,int v){
    node *p=++New;
    p->v=v;
    p->nxt=adj[u];
    adj[u]=p;
    p=++New;
    p->v=u;
    p->nxt=adj[v];
    adj[v]=p;
}

int n,m;
int u[MAXM+10],v[MAXM+10];

int cnt;
int dfn[MAXN+10],low[MAXN+10],now;
int mark[MAXN+10],num[MAXN+10];
bool instk[MAXN+10];
stack<int>stk;
void tarjan(int x,int f){
    dfn[x]=low[x]=++now;
    stk.push(x),instk[x]=true;

    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        if(!dfn[p->v])tarjan(p->v,x),low[x]=min(low[x],low[p->v]);
        if(instk[p->v])low[x]=min(low[x],dfn[p->v]);
    }

    if(dfn[x]==low[x]){
        ++cnt;
        while(stk.top()!=x)
            mark[stk.top()]=cnt,++num[cnt],instk[stk.top()]=false,stk.pop();
        mark[x]=cnt,++num[cnt],instk[x]=false,stk.pop();
    }
}

int sta[MAXN+10],tar[MAXN+10],total;
bool vis[MAXN+10];
int dep[MAXN+10];
int dfs(int x,int f){
    dep[x]=dep[f]+1,vis[x]=true;
    int ret=x,t;
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        t=dfs(p->v,x);
        if(dep[t]>dep[ret])ret=t;
    }
    return ret;
}
bool inlink[MAXN+10];
bool find_link(int x,int tar,int f){
    if(x==tar)return (inlink[x]=true);
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        if(find_link(p->v,tar,x))
            return (inlink[x]=true);
    }
    return (inlink[x]=false);
}

int sz[MAXN+10];
int getans(int x,int f){
    sz[x]=1;
    int ret=0,t=0;
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        ret+=getans(p->v,x);
        sz[x]+=sz[p->v];
        if(!inlink[p->v])t+=sz[p->v]-1;
    }
    return ret+(inlink[x]?t:0);
}

int main(){
    //freopen("worm.in","r",stdin);
    //freopen("worm.out","w",stdout);

    Read(n),Read(m);
    for(int i=1;i<=m;++i)
        Read(u[i]),Read(v[i]);

    init();
    for(int i=1;i<=m;++i)
        addedges(u[i],v[i]);

    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(instk,0,sizeof(instk));
    cnt=now=0;
    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i,0);

    init();
    for(int i=1;i<=m;++i)
        if(mark[u[i]]!=mark[v[i]])addedges(mark[u[i]],mark[v[i]]);

    memset(vis,0,sizeof(vis));
    total=0;
    for(int i=1;i<=cnt;++i){
        if(vis[i])continue;
        sta[++total]=dfs(i,0);
    }
    for(int i=1;i<=total;++i)
        tar[i]=dfs(sta[i],0);
    for(int i=1;i<=total;++i)
        find_link(sta[i],tar[i],0);

    int ans=total-1;
    for(int i=1;i<=total;++i)
        ans+=getans(sta[i],0);
    for(int i=1;i<=cnt;++i)
        ans+=num[i]-1;

    printf("%d\n",ans);
}


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<time.h>
using namespace std;

typedef long long int LL;
const int MAXN = 2000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;

template<class T>
void Read(T &x){
    x=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(flag)x=-x;
}

struct node{
    int v;
    node *nxt;
}*adj[MAXN+10],Edges[MAXM*2+10],*New;
void init_edge(){memset(adj,0,sizeof(adj)),New=Edges;}
void addedges(int u,int v){
    node *p=++New;
    p->v=v;
    p->nxt=adj[u];
    adj[u]=p;
    p=++New;
    p->v=u;
    p->nxt=adj[v];
    adj[v]=p;
}

int n,m;
int u[MAXM+10],v[MAXM+10];
int dfn[MAXN+10],low[MAXN+10],cnt;
int bel[MAXN+10],tot;
int d[MAXN+10];
stack<int>stk;
void tarjan(int x,int f){
    dfn[x]=low[x]=++cnt;
    stk.push(x);
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        if(!dfn[p->v]){
            tarjan(p->v,x);
            low[x]=min(low[x],low[p->v]);
        }
        else low[x]=min(low[x],dfn[p->v]);
    }

    if(dfn[x]==low[x]){
        ++tot;
        while(stk.top()!=x){
            bel[stk.top()]=tot;
            stk.pop();
        }
        bel[x]=tot;
        stk.pop();
    }
}

int dep[MAXN+10],mxd[MAXN+10];
bool vis[MAXN+10];
void dfs(int x,int f){
    vis[x]=true,dep[x]=dep[f]+1,mxd[x]=x;
    for(node *p=adj[x];p!=NULL;p=p->nxt)
        if(p->v!=f){
            dfs(p->v,x);
            if(dep[mxd[p->v]]>dep[mxd[x]])
                mxd[x]=mxd[p->v];
        }
}

int main(){
    Read(n),Read(m);
    init_edge();
    for(int i=1;i<=m;++i){
        Read(u[i]),Read(v[i]);
        addedges(u[i],v[i]);
    }

    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i,0);

    init_edge();
    for(int i=1;i<=m;++i)
        if(bel[u[i]]!=bel[v[i]]){
            addedges(bel[u[i]],bel[v[i]]);
            ++d[bel[u[i]]],++d[bel[v[i]]];
        }

    int block=0,ans=0;
    for(int i=1;i<=tot;++i){
        if(vis[i])continue;
        ++block;
        int r;
        dfs(i,0),r=mxd[i];
        dfs(r,0);
        ans+=dep[mxd[r]];
    }

    int cnt1=0;
    for(int i=1;i<=tot;++i)
        cnt1+=(d[i]==1);

    ans=ans+cnt1-2*block-(block-1);
    printf("%d\n",n-ans);
}


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<time.h>
using namespace std;

typedef long long int LL;
const int MAXN = 2000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;

template<class T>
void Read(T &x){
    x=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(flag)x=-x;
}

struct node{
    int v;
    node *nxt;
}*adj[MAXN+10],Edges[MAXM*2+10],*New;
void init_edge(){memset(adj,0,sizeof(adj)),New=Edges;}
void addedges(int u,int v){
    node *p=++New;
    p->v=v;
    p->nxt=adj[u];
    adj[u]=p;
    p=++New;
    p->v=u;
    p->nxt=adj[v];
    adj[v]=p;
}

int n,m;
int u[MAXM+10],v[MAXM+10];
int dfn[MAXN+10],low[MAXN+10],cnt;
int bel[MAXN+10],tot;
int d[MAXN+10];
stack<int>stk;
void tarjan(int x,int f){
    dfn[x]=low[x]=++cnt;
    stk.push(x);
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(p->v==f)continue;
        if(!dfn[p->v]){
            tarjan(p->v,x);
            low[x]=min(low[x],low[p->v]);
        }
        else low[x]=min(low[x],dfn[p->v]);
    }

    if(dfn[x]==low[x]){
        ++tot;
        while(stk.top()!=x){
            bel[stk.top()]=tot;
            stk.pop();
        }
        bel[x]=tot;
        stk.pop();
    }
}

int dep[MAXN+10],mxd[MAXN+10];
bool vis[MAXN+10];
void dfs(int x,int f){
    vis[x]=true,dep[x]=dep[f]+1,mxd[x]=x;
    for(node *p=adj[x];p!=NULL;p=p->nxt)
        if(p->v!=f){
            dfs(p->v,x);
            if(dep[mxd[p->v]]>dep[mxd[x]])
                mxd[x]=mxd[p->v];
        }
}

int main(){
    Read(n),Read(m);
    init_edge();
    for(int i=1;i<=m;++i){
        Read(u[i]),Read(v[i]);
        addedges(u[i],v[i]);
    }

    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i,0);

    init_edge();
    for(int i=1;i<=m;++i)
        if(bel[u[i]]!=bel[v[i]]){
            addedges(bel[u[i]],bel[v[i]]);
            ++d[bel[u[i]]],++d[bel[v[i]]];
        }

    int block=0,ans=0;
    for(int i=1;i<=tot;++i){
        if(vis[i])continue;
        ++block;
        int r;
        dfs(i,0),r=mxd[i];
        dfs(r,0);
        ans+=dep[mxd[r]];
        ans-=min(dep[mxd[r]],2);
    }

    int cnt1=0;
    for(int i=1;i<=tot;++i)
        cnt1+=(d[i]<2);

    ans=ans+cnt1-(block-1);
    printf("%d\n",n-ans);
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <climits>
#include <numeric>
#include <vector>
using namespace std;
const int MAX_N = 2000 + 10, INF = ~0U >> 3;
//first we should merge every cycle!
//run a 2-connected-component algorithm :)
vector<int> E[MAX_N];
int n, m;

bool vis[MAX_N];
int low[MAX_N], ord[MAX_N], pt = 0;
int stack[MAX_N], top = 0;
int nId;
int id[MAX_N];

void dfs(int u, int par) {
	vis[u] = true;
	low[u] = ord[u] = pt++;
	stack[top++] = u;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e)
		if (*e != par) {
			if (!vis[*e]) {
				dfs(*e, u);
				low[u] = min(low[u], low[*e]);
			} else {
				low[u] = min(low[u], ord[*e]);
			}
		}
	if (par == -1 || low[u] == ord[u]) {
		while (top > 0) {
			int v = stack[--top];
			id[v] = nId;
			if (v == u)
				break;
		}
		nId++;
	}
}

int ans;

void merge() {
	for (int i = 0; i < n; ++i) {
		if (!vis[i])
			dfs(i, -1);
	}
	static vector<int> tmp[MAX_N];
	for (int i = 0; i < n; ++i) {
		for (vector<int>::iterator e = E[i].begin(); e != E[i].end(); ++e) {
			if (id[i] < id[*e]) {
				int u = id[i], v = id[*e];
				tmp[u].push_back(v);
				tmp[v].push_back(u);
			}
		}
	}
	ans = n - nId;
	n = nId;
	for (int i = 0; i < n; ++i) {
		E[i] = tmp[i];
	}
}

int d[MAX_N];
int dia;

int cnt;
pair<int, int> memo[MAX_N][MAX_N];
bool save[MAX_N][MAX_N];
pair<int, int> calc(int u, int par) {
	pair<int, int>&ret = memo[u][par + 1];
	if (save[u][par + 1])
		return ret;
	save[u][par + 1] = true;
	int ans = 0, size = 1;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e) {
		if (*e != par) {
			pair<int, int> t = calc(*e, u);
			ans += min(t.second - 1, 1 + t.first);
			size += t.second;
		}
	}
	return ret = make_pair(ans, size);
}

vector<int> vs;
void dfs3(int u, int par) {
	vs.push_back(u);
	vis[u] = true;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e) {
		if (*e != par)
			dfs3(*e, u);
	}
}

int mi;
void dfs2(int u, int par, int p) {
	//end here
	int tmp = p + calc(u, par).first;
//	if (tmp == 0) {
//		cout << u << " " << par << endl;
//	}
	mi = min(mi, tmp);

	int total = 0;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e) {
		if (*e != par) {
			pair<int, int> ret = calc(*e, u);
			total += min(ret.first + 1, ret.second - 1);
		}
	}

	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e)
		if (*e != par) {
			pair<int, int> ret = calc(*e, u);
			total -= min(ret.first + 1, ret.second - 1);
			dfs2(*e, u, p + total);
			total += min(ret.first + 1, ret.second - 1);
		}
}

void work() {

	for (int i = 0; i < n; ++i) {
		d[i] = E[i].size() - 1;
	}
	memset(vis, 0, sizeof vis);
	int nComp = 0;
	for (int i = 0; i < n; ++i)
		if (!vis[i]) {
			vs.clear();
			dfs3(i, -1);
			mi = INF;
			for (vector<int>::iterator e = vs.begin(); e != vs.end(); ++e) {
				dfs2(*e, -1, 0);
			}
			ans += mi;
			++nComp;
		}
	ans += nComp - 1;
	cout << ans << endl;
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < m; ++i) {
		int a, b;
		cin >> a >> b;
		--a, --b;
		E[a].push_back(b), E[b].push_back(a);
	}
	merge();
//now every one is a tree!
	work();
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <climits>
#include <numeric>
#include <vector>
using namespace std;
const int MAX_N = 2000 + 10, INF = ~0U >> 3;
//first we should merge every cycle!
//run a 2-connected-component algorithm :)
vector<int> E[MAX_N];
int n, m;

bool vis[MAX_N];
int low[MAX_N], ord[MAX_N], pt = 0;
int stack[MAX_N], top = 0;
int nId;
int id[MAX_N];

void dfs(int u, int par) {
	vis[u] = true;
	low[u] = ord[u] = pt++;
	stack[top++] = u;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e)
		if (*e != par) {
			if (!vis[*e]) {
				dfs(*e, u);
				low[u] = min(low[u], low[*e]);
			} else {
				low[u] = min(low[u], ord[*e]);
			}
		}
	if (par == -1 || low[u] == ord[u]) {
		while (top > 0) {
			int v = stack[--top];
			id[v] = nId;
			if (v == u)
				break;
		}
		nId++;
	}
}

int ans;

void merge() {
	for (int i = 0; i < n; ++i) {
		if (!vis[i])
			dfs(i, -1);
	}
	static vector<int> tmp[MAX_N];
	for (int i = 0; i < n; ++i) {
		for (vector<int>::iterator e = E[i].begin(); e != E[i].end(); ++e) {
			if (id[i] < id[*e]) {
				int u = id[i], v = id[*e];
				tmp[u].push_back(v);
				tmp[v].push_back(u);
			}
		}
	}
	ans = n - nId;
	n = nId;
	for (int i = 0; i < n; ++i) {
		E[i] = tmp[i];
	}
}

int d[MAX_N];
int dia;

int cnt;
int dfs2(int u, int par) { //return max-depth
	vis[u] = true;
	++cnt;
	int p = 0;
	for (vector<int>::iterator e = E[u].begin(); e != E[u].end(); ++e) {
		if (*e != par) {
			int cur = max(dfs2(*e, u), 0);
			dia = max(dia, d[u] + p + cur);
			p = max(p, cur);
		}
	}
	p += d[u];
	dia = max(dia, p);
	return p;
}
void work() {
	for (int i = 0; i < n; ++i) {
		d[i] = E[i].size() - 1;
	}
	memset(vis, 0, sizeof vis);
	int nComp = 0;
	for (int i = 0; i < n; ++i) {
		if (!vis[i]) {
			dia = -INF;
			cnt = 0;
			dfs2(i, -1);
			dia += 2;
			++nComp;
			ans += cnt - dia;
		}
	}
	ans += nComp - 1;
	cout << ans << endl;
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < m; ++i) {
		int a, b;
		cin >> a >> b;
		--a, --b;
		E[a].push_back(b), E[b].push_back(a);
	}
	merge();
	//now every one is a tree!
	work();
	return 0;
}


#include <vector>
#include <cstdio>
#include <set>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <numeric>
#include <queue>
#include <iostream>
#include <string>
#include <cstring>
#include <utility>
#define sz(a) ((int)(a).size())
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define Rep(i,j,k) for (int i=(j); i<=(k); i++)
#define Repd(i,j,k) for (int i=(j); i>=(k); i--)
#define ALL(c) (c).begin(),(c).end()
#define TR(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define SUM(a) accumulate(all(a),string())
#define online1
#define RAND ((rand()<<15)+rand())
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long LL;
#define N 2100

int n, m;
VI E[N], E2[N];
bool vi[N];
int dep[N], low[N], f[N];

void dfs(int x, int fa){
	dep[x]=dep[fa]+1;
	low[x]=dep[x];
	TR(E[x],y)
		if (*y!=fa){
			if (dep[*y]){
				low[x]=min(low[x], dep[*y]);
			}else{
				dfs(*y,x);
				low[x]=min(low[x], low[*y]);
			}
		}
	if (low[x]<dep[x]){
		f[x]=fa;
	}else
		f[x]=x;
}

int getf(int x){
	if (x==f[x]) return x;
	return f[x]=getf(f[x]);
}

void find(int x, VI &root){
	vi[x]=1;
	root.pb(x);
	TR(E[x],y)
		if (!vi[*y])
			find(*y,root);
}

int p[N], q[N];

int calcq(int x, int fa){
	if (q[x]!=-1) return q[x];
	int ret=0;
	TR(E[x],y)
		if (*y!=fa)
			ret+=calcq(*y,x);
	return q[x]=max(1,ret);
}

int calcp(int x, int fa){
	if (p[x]!=-1) return p[x];
	int ret=1, sum=0;
	TR(E[x],y)
		if (*y!=fa)
			sum+=calcq(*y,x);
	TR(E[x],y)
		if (*y!=fa)
			ret=max(ret, 1+sum-q[*y]+calcp(*y,x));
	return p[x]=ret;
}

int solve(int x){
	VI root;
	find(x,root);
	int ret=0;
	TR(root,x){
		memset(p,0xff,sizeof p);
		memset(q,0xff,sizeof q);
		ret=max(ret,calcp(*x,0));
	}
	return ret;
}

int main(){
	cin>>n>>m;
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		E[x].pb(y);
		E[y].pb(x);
	}

	/*
	Rep(x,1,n){
		cout<<x<<":";
		TR(E[x],y) cout<<*y<<" ";
		cout<<endl;
	}
	*/

	Rep(x,1,n)
		if (!dep[x])
			dfs(x,0);

	Rep(x,1,n)
		TR(E[x],y){
			int xx=getf(x), yy=getf(*y);
			if (xx!=yy)
				E2[xx].pb(yy); //cout<<xx<<" "<<yy<<endl;
		}
	Rep(x,1,n)
		E[x]=E2[x];

	int ans=1;
	Rep(x,1,n)
		if (getf(x)==x && !vi[x])
			ans+=solve(x)-1;

	cout<<n-ans<<endl;

    return 0;
}


#include <vector>
#include <cstdio>
#include <set>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <numeric>
#include <queue>
#include <iostream>
#include <string>
#include <cstring>
#include <utility>
#define sz(a) ((int)(a).size())
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define Rep(i,j,k) for (int i=(j); i<=(k); i++)
#define Repd(i,j,k) for (int i=(j); i>=(k); i--)
#define ALL(c) (c).begin(),(c).end()
#define TR(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define SUM(a) accumulate(all(a),string())
#define online1
#define RAND ((rand()<<15)+rand())
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> II;
typedef long long LL;
#define N 2100

int n, m;
VI E[N], E2[N];
bool vi[N];
int dep[N], low[N], f[N];

void dfs(int x, int fa){
	dep[x]=dep[fa]+1;
	low[x]=dep[x];
	TR(E[x],y)
		if (*y!=fa){
			if (dep[*y]){
				low[x]=min(low[x], dep[*y]);
			}else{
				dfs(*y,x);
				low[x]=min(low[x], low[*y]);
			}
		}
	if (low[x]<dep[x]){
		f[x]=fa;
	}else
		f[x]=x;
}

int getf(int x){
	if (x==f[x]) return x;
	return f[x]=getf(f[x]);
}

void find(int x, VI &root){
	vi[x]=1;
	root.pb(x);
	TR(E[x],y)
		if (!vi[*y])
			find(*y,root);
}

int calc(int x, int fa){
	int ret=1, son=0;
	TR(E[x],y)
		if (*y!=fa)
			son++;
	TR(E[x],y)
		if (*y!=fa)
			ret=max(ret, calc(*y,x)+son);
	return ret;
}

int solve(int x){
	VI root;
	find(x,root);
	int ret=0;
	TR(root,x)
		ret=max(ret,calc(*x,0));
	return ret;
}

int main(){

	cin>>n>>m;
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		E[x].pb(y);
		E[y].pb(x);
	}

	Rep(x,1,n)
		if (!dep[x])
			dfs(x,0);

	Rep(x,1,n)
		TR(E[x],y){
			int xx=getf(x), yy=getf(*y);
			if (xx!=yy)
				E2[xx].pb(yy); //cout<<xx<<" "<<yy<<endl;
		}
	Rep(x,1,n)
		E[x]=E2[x];

	int ans=1;
	Rep(x,1,n)
		if (getf(x)==x && !vi[x])
			ans+=solve(x)-1;

	cout<<n-ans<<endl;

    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int ja[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

inline int FIND( int x ) {
  return x == ja[x] ? x : ja[x] = FIND( ja[x] );
}
inline void JOIN( int x, int y ) { /* y na x */
  ja[ FIND( y ) ] = FIND( x );
}

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  if ( parent != -1 ) parent = FIND( parent );
  bio[x] = tajm;
  bool parent_used = false;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = FIND( node[x][i] );
    if ( y == parent && !parent_used ) { parent_used = true; continue; }
    if ( y == x ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      cycle_start = y;
      return true;
    }
    if ( y == parent ) continue;
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    } else if ( cycle_start )
      return false;
  }
  return false;
}

int MERGE( int x, int y ) {
  x = FIND( x ); y = FIND( y );
  if ( x == y ) return x;
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  JOIN( x, y );
  ++operation;
  return x;
}

void remove_cycles( void ) {
  ++tajm;
  for ( int i = 1; i <= N; ++i ) {
    if ( FIND( i ) != i ) continue;
    cycle_start = 0;
    v.clear();
    ++tajm;
    DFS( i, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( x, y ) );
      }
      --i;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = FIND( node[x][i] );
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = FIND( node[x][i] );
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = FIND( node[x][i] );
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    ja[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || FIND( i ) != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0; ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    max_dist = 0; ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      cycle_start = y;
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
}

int MERGE( int x, int y ) {
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  for ( int i = 1; i <= N; ++i ) {
    if ( me[i] != i ) continue;
    if ( bio[i] == tajm ) continue;
    cycle_start = 0;
    v.clear();
    ++tajm;
    DFS( i, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( x, y ) );
      }
      --i;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0;
    ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
}

int MERGE( int x, int y ) {
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  for ( int i = 1; i <= N; ++i ) {
    if ( me[i] != i ) continue;
    cycle_start = 0;
    v.clear();
    DFS( 1, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( x, y ) );
      }
      ++tajm;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0;
    ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  bool parent_used = false;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent && !parent_used ) { parent_used = true; continue; }
    if ( y == x ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      cycle_start = y;
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
  return false;
}

int MERGE( int x, int y ) {
  x = me[x]; y = me[y];
  if ( x == y ) return x;
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  ++tajm;
  for ( int i = 1; i <= N; ++i ) {
    if ( me[i] != i ) continue;
    cycle_start = 0;
    v.clear();
    ++tajm;
    DFS( i, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( me[x], me[y] ) );
      }
      --i;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0; ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    max_dist = 0; ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
}

int MERGE( int x, int y ) {
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  for ( int i = 1; i <= N; ++i ) {
    cycle_start = 0;
    v.clear();
    DFS( 1, -1 );

    if ( v.size() ) {
      while ( v.size() > 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( x, y ) );
      }
      ++tajm;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0;
    ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      cycle_start = y;
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
  return false;
}

int MERGE( int x, int y ) {
  x = me[x]; y = me[y];
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  ++tajm;
  for ( int i = 1; i <= N; ++i ) {
    if ( me[i] != i ) continue;
    if ( bio[i] == tajm ) continue;
    cycle_start = 0;
    v.clear();
    ++tajm;
    DFS( i, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( me[x], me[y] ) );
      }
      --i;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0; ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    max_dist = 0; ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#define MAX 2004

using namespace std;

vector < int > node[MAX];
int me[MAX];
int bio[MAX];
int N, M;
int tajm;
bool onroute[MAX];

vector < int > v;
int cycle_start;

int operation = 0;

bool DFS( int x, int parent ) {
  bio[x] = tajm;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent || y == x ) continue;
    if ( bio[y] == tajm ) {
      v.push_back( y );
      cycle_start = y;
      return true;
    }
    if ( DFS( y, x ) ) {
      v.push_back( y );
      return cycle_start != x;
    }
  }
  return false;
}

int MERGE( int x, int y ) {
  x = me[x]; y = me[y];
  if ( node[y].size() > node[x].size() ) swap( x, y );
  node[x].insert( node[x].end(), node[y].begin(), node[y].end() );
  me[y] = x;
  ++operation;
  return x;
}

void remove_cycles( void ) {
  ++tajm;
  for ( int i = 1; i <= N; ++i ) {
    if ( me[i] != i ) continue;
    if ( bio[i] == tajm ) continue;
    cycle_start = 0;
    v.clear();
    ++tajm;
    DFS( i, -1 );

    if ( v.size() ) {
      while ( v.size() >= 2 ) {
        int x = v.back(); v.pop_back();
        int y = v.back(); v.pop_back();
        v.push_back( MERGE( me[x], me[y] ) );
      }
      --i;
    }
  }
}

int max_dist, max_dist_x;
int component_size;

void distDFS( int x, int parent, int dist ) {
  bio[x] = tajm;
  ++component_size;
  if ( dist > max_dist ) { max_dist = dist; max_dist_x = x; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( bio[y] == tajm ) continue;
    distDFS( y, x, dist + 1 );
  }
}
bool routeDFS( int x, int target, int parent ) {
  if ( x == target ) { onroute[x] = true; v.push_back( x ); return true; }
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( y == parent ) continue;
    if ( routeDFS( y, target, x ) ) {
      onroute[x] = true;
      v.push_back( x );
      return true;
    }
  }
  return false;
}

void mergeDFS( int x, int parent ) {
  bio[x] = tajm;
  if ( node[x].size() > 1 && !onroute[x] )
    ++operation;
  for ( int i = 0; i < node[x].size(); ++i ) {
    int y = me[node[x][i]];
    if ( onroute[y] || y == parent || bio[y] == tajm ) continue;
    mergeDFS( y, x );
  }
}

int main(void) {
  int A, B;

  scanf("%d%d", &N, &M);
  for ( int i = 0; i < M; ++i ) {
    scanf("%d%d", &A, &B);
    node[A].push_back( B );
    node[B].push_back( A );
  }

  for ( int i = 1; i <= N; ++i )
    me[i] = i;

  remove_cycles();

  memset( bio, 0, sizeof( bio ) );
  int components = 0;
  for ( int i = 1; i <= N; ++i ) {
    if ( bio[i] || me[i] != i ) continue;
    ++components;
    component_size = 0;

    max_dist = 0; ++tajm; distDFS( i, -1, 0 ); int D = max_dist_x;
    if ( component_size <= 3 ) continue;
    max_dist = 0; ++tajm; distDFS( D, -1, 0 ); int E = max_dist_x;

    v.clear();
    routeDFS( D, E, -1 );
    ++tajm;
    for ( int j = 0; j < v.size(); ++j )
      mergeDFS( v[j], -1 );

  }

  operation += components - 1;
  printf("%d\n", operation);
  return 0;
}


#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define Fit(it,c) for (typeof(c.begin())it=c.begin();it!=c.end();it++)
#define Clear(a) memset(a,0,sizeof(a))
#define Neg(a) memset(a,255,sizeof(a))
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define PII pair<int,int>
#define maxn 2012

queue<int> q;
set<int> chain;
set<PII> bridge;
vector<int> e[maxn];
int dfn[maxn],low[maxn],blg[maxn],d[maxn];
int n,m,ans,idx,far,fu,fv;
bool vis[maxn];
bool found;

void init()
{
	scanf("%d %d\n",&n,&m);
	int u,v;
	for (int i=0;i<m;i++)
	{
		scanf("%d %d\n",&u,&v);
		e[u].pb(v); e[v].pb(u);
	}
}

void dfs(int a,int u)
{
	dfn[u]=++idx;
	low[u]=dfn[u];
	Fit(it,e[u])
	if (dfn[*it]<0)
	{
		dfs(u,*it);
		low[u]=min(low[u],low[*it]);
      	if (low[*it]>dfn[u])
		{
			bridge.insert(mp(u,*it));
			bridge.insert(mp(*it,u));
	  	}
	}
	else if (*it!=a) low[u]=min(low[u],dfn[*it]);
}

void dfsa(int u)
{
	vis[u]=1; blg[u]=idx; ans++;
	Fit(it,e[u])
	if (!vis[*it] && !bridge.count(mp(u,*it))) dfsa(*it);
}

void bfs1(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		vis[u]=1;
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void bfs2(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void makechain(int a,int u)
{
	chain.insert(u);
	if (u==fv)
	{
		found=1;
		return;
	}
	Fit(it,e[u])
	if (*it!=a)
	{
		makechain(u,*it);
		if (found) return;
	}
	chain.erase(u);
}

void DP(int dep,int a,int u)
{
	bool flag=0;
	Fit(it,e[u])
	if (!chain.count(*it) && *it!=a)
	{
		DP(dep+1,u,*it);
		if (dep) flag=1;
	}
	if (flag) ans++;
}

void work()
{
	Neg(dfn); Neg(low);
	for (int i=1;i<=n;i++)
	if (dfn[i]<0)
	{
		ans++; idx=0;
		dfs(0,i);
	}
	--ans;
	Clear(vis); idx=0;
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		idx++; dfsa(i);	ans--;
	}
	for (int i=1;i<=n;i++) e[i].clear();
	Fit(it,bridge) e[blg[it->x]].pb(blg[it->y]);
	Clear(vis);
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		bfs1(blg[i]);fu=far;
		bfs2(far);fv=far;
		found=0; chain.clear();
		makechain(0,fu);
		Fit(it,chain) DP(0,0,*it);
	}
	printf("%d\n",ans);
}

int main()
{
	init();
	work();
}


#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define Fit(it,c) for (typeof(c.begin())it=c.begin();it!=c.end();it++)
#define Clear(a) memset(a,0,sizeof(a))
#define Neg(a) memset(a,255,sizeof(a))
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define PII pair<int,int>
#define maxn 2012

queue<int> q;
set<int> chain;
set<PII> bridge;
vector<int> e[maxn];
int dfn[maxn],low[maxn],blg[maxn],d[maxn];
int n,m,ans,idx,far,fu,fv;
bool vis[maxn];
bool found;

void init()
{
	scanf("%d %d\n",&n,&m);
	int u,v;
	for (int i=0;i<m;i++)
	{
		scanf("%d %d\n",&u,&v);
		e[u].pb(v); e[v].pb(u);
	}
}

void dfs(int a,int u)
{
	dfn[u]=++idx;
	low[u]=dfn[u];
	Fit(it,e[u])
	if (dfn[*it]<0)
	{
		dfs(u,*it);
		low[u]=min(low[u],low[*it]);
      	if (low[*it]>dfn[u])
		{
			bridge.insert(mp(u,*it));
			bridge.insert(mp(*it,u));
	  	}
	}
	else if (*it!=a) low[u]=min(low[u],dfn[*it]);
}

void dfsa(int u)
{
	vis[u]=1; blg[u]=idx; ans++;
	Fit(it,e[u])
	if (!vis[*it] && !bridge.count(mp(u,*it))) dfsa(*it);
}

void bfs1(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		vis[u]=1;
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void bfs2(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void makechain(int a,int u)
{
	chain.insert(u);
	if (u==fv)
	{
		found=1;
		return;
	}
	Fit(it,e[u])
	if (*it!=a)
	{
		makechain(u,*it);
		if (found) return;
	}
	chain.erase(u);
}

void DP(int dep,int a,int u)
{
	Fit(it,e[u])
	if (!chain.count(*it) && *it!=a) DP(dep+1,u,*it);
	if (dep>1) ans++;
}

void work()
{
	Neg(dfn); Neg(low);
	for (int i=1;i<=n;i++)
	if (dfn[i]<0)
	{
		ans++; idx=0;
		dfs(0,i);
	}
	--ans;
	Clear(vis); idx=0;
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		idx++; dfsa(i);	ans--;
	}
	for (int i=1;i<=n;i++) e[i].clear();
	Fit(it,bridge) e[blg[it->x]].pb(blg[it->y]);

	Clear(vis);
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		bfs1(blg[i]);fu=far;
		bfs2(far);fv=far;
		found=0; chain.clear();
		makechain(0,fu);
		Fit(it,chain) DP(0,0,*it);
	}
	printf("%d\n",ans);
}

int main()
{
	init();
	work();
}


#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define Fit(it,c) for (typeof(c.begin())it=c.begin();it!=c.end();it++)
#define Clear(a) memset(a,0,sizeof(a))
#define Neg(a) memset(a,255,sizeof(a))
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define PII pair<int,int>
#define maxn 2012

queue<int> q;
set<int> chain;
set<PII> bridge;
vector<int> e[maxn];
int dfn[maxn],low[maxn],blg[maxn],d[maxn];
int n,m,ans,idx,far,fu,fv;
bool vis[maxn],done[maxn];
bool found;

void init()
{
	scanf("%d %d\n",&n,&m);
	int u,v;
	for (int i=0;i<m;i++)
	{
		scanf("%d %d\n",&u,&v);
		e[u].pb(v); e[v].pb(u);
	}
}

void dfs(int a,int u)
{
	dfn[u]=++idx;
	low[u]=dfn[u];
	Fit(it,e[u])
	if (dfn[*it]<0)
	{
		dfs(u,*it);
		low[u]=min(low[u],low[*it]);
      	if (low[*it]>dfn[u])
		{
			bridge.insert(mp(u,*it));
			bridge.insert(mp(*it,u));
	  	}
	}
	else if (*it!=a) low[u]=min(low[u],dfn[*it]);
}

void dfsa(int u)
{
	vis[u]=1; blg[u]=idx; ans++;
	Fit(it,e[u])
	if (!vis[*it] && !bridge.count(mp(u,*it))) dfsa(*it);
}

void bfs1(int u)
{
	int maxd=0;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1; far=u;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		done[u]=1;
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void bfs2(int u)
{
	int maxd=0;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1; far=u;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void makechain(int a,int u)
{
	chain.insert(u);
	if (u==fv)
	{
		found=1;
		return;
	}
	Fit(it,e[u])
	if (*it!=a)
	{
		makechain(u,*it);
		if (found) return;
	}
	chain.erase(u);
}

void DP(int dep,int a,int u)
{
	bool flag=0;
	Fit(it,e[u])
	if (!chain.count(*it) && *it!=a)
	{
		DP(dep+1,u,*it);
		if (dep) flag=1;
	}
	if (chain.count(u)) flag=0;
	if (flag) ans++;
}

void work()
{
	Neg(dfn); Neg(low);
	for (int i=1;i<=n;i++)
	if (dfn[i]<0)
	{
		ans++; idx=0;
		dfs(0,i);
	}
	--ans;
	Clear(vis); idx=0;
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		idx++; dfsa(i);	ans--;
	}
	for (int i=1;i<=n;i++) e[i].clear();
	Fit(it,bridge) e[blg[it->x]].pb(blg[it->y]);
	for (int i=1;i<=idx;i++)
	if (!done[i])
	{
		bfs1(i);fu=far;
		bfs2(far);fv=far;
		found=0; chain.clear();
		makechain(0,fu);
		Fit(it,chain) DP(0,0,*it);
	}
	printf("%d\n",ans);
}

int main()
{
	init();
	work();
}


#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define Fit(it,c) for (typeof(c.begin())it=c.begin();it!=c.end();it++)
#define Clear(a) memset(a,0,sizeof(a))
#define Neg(a) memset(a,255,sizeof(a))
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define PII pair<int,int>
#define maxn 2012

queue<int> q;
set<int> chain;
set<PII> bridge;
vector<int> e[maxn];
int dfn[maxn],low[maxn],blg[maxn],d[maxn];
int n,m,ans,idx,far,fu,fv;
bool vis[maxn];
bool found;

void init()
{
	scanf("%d %d\n",&n,&m);
	int u,v;
	for (int i=0;i<m;i++)
	{
		scanf("%d %d\n",&u,&v);
		e[u].pb(v); e[v].pb(u);
	}
}

void dfs(int a,int u)
{
	dfn[u]=++idx;
	low[u]=dfn[u];
	Fit(it,e[u])
	if (dfn[*it]<0)
	{
		dfs(u,*it);
		low[u]=min(low[u],low[*it]);
      	if (low[*it]>dfn[u])
		{
			bridge.insert(mp(u,*it));
			bridge.insert(mp(*it,u));
	  	}
	}
	else if (*it!=a) low[u]=min(low[u],dfn[*it]);
}

void dfsa(int u)
{
	vis[u]=1; blg[u]=idx; ans++;
	Fit(it,e[u])
	if (!vis[*it] && !bridge.count(mp(u,*it))) dfsa(*it);
}

void bfs1(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		vis[u]=1;
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void bfs2(int u)
{
	int maxd=-1;
	Clear(d); Clear(vis);
	q.push(u); d[u]=0; vis[u]=1;
	while (!q.empty())
	{
		u=q.front(); q.pop();
		Fit(it,e[u])
		if (!vis[*it])
		{
			vis[*it]=1;
			q.push(*it);
			d[*it]=d[u]+1;
			if (d[*it]>maxd)
			{
				maxd=d[*it];
				far=*it;
			}
		}
	}
}

void makechain(int a,int u)
{
	chain.insert(u);
	if (u==fv)
	{
		found=1;
		return;
	}
	Fit(it,e[u])
	if (*it!=a)
	{
		makechain(u,*it);
		if (found) return;
	}
	chain.erase(u);
}

void DP(int dep,int a,int u)
{
	bool flag=0;
	Fit(it,e[u])
	if (!chain.count(*it) && *it!=a)
	{
		DP(dep+1,u,*it);
		if (dep) flag=1;
	}
	if (chain.count(u)) flag=0;
	if (flag) ans++;
}

void work()
{
	Neg(dfn); Neg(low);
	for (int i=1;i<=n;i++)
	if (dfn[i]<0)
	{
		ans++; idx=0;
		dfs(0,i);
	}
	--ans;
	Clear(vis); idx=0;
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		idx++; dfsa(i);	ans--;
	}
	for (int i=1;i<=n;i++) e[i].clear();
	Fit(it,bridge) e[blg[it->x]].pb(blg[it->y]);
	Clear(vis);
	for (int i=1;i<=n;i++)
	if (!vis[i])
	{
		bfs1(blg[i]);fu=far;
		bfs2(far);fv=far;
		found=0; chain.clear();
		makechain(0,fu);
		Fit(it,chain) DP(0,0,*it);
	}
	printf("%d\n",ans);
}

int main()
{
	init();
	work();
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <set>
#include <algorithm>
#include <map>
#include <bitset>
#include <vector>
#include <queue>
#include <utility>
#include <functional>
#include <sstream>
#include <list>
#include <complex>

#define maxlongint 2147483647
#define biglongint 2139062143
#define LL long long
#define ULL unsigned long long
#define p_b push_back
#define m_p make_pair
#define l_b lower_bound

using namespace std;

typedef pair<int,int> PII;
typedef pair<pair<int,int>,int> PIII;

const int maxn=2005;
vector<int> a[maxn],f[maxn];
int dfn[maxn],low[maxn],where[maxn],hash[maxn],stack[maxn],big[maxn][maxn],leaf[maxn],sum[maxn];
int n,m,k,xc,yc,ans,nowans,tot,o,top;

void dfs(int s,int fa)
{
    int c;
    ++o;
    dfn[s]=o;
    low[s]=o;
    ++top;
    stack[top]=s;
    for (int i=0;i<a[s].size();i++)
    {
        c=a[s][i];
        if (c==fa) continue;
        if (dfn[c]==0)
        {
            dfs(c,s);
            low[s]=min(low[s],low[c]);
        }
        else
            low[s]=min(low[s],dfn[c]);
    }
    if (dfn[s]==low[s])
    {
        ++tot;
        while (stack[top+1]!=s)
        {
            where[stack[top]]=tot;
            low[stack[top]]=maxlongint;
            dfn[stack[top]]=maxlongint;
            --top;
        }
    }
}

void findmax(int s,int nows)
{
    int c;
    hash[s]=1;
    //cout<<s<<" "<<nows<<endl;
    if (leaf[s]==1)
    {
        nowans=min(nowans,nows);
    }
    else
    {
        for (int i=0;i<f[s].size();i++)
        {
            c=f[s][i];
            if (hash[c]==0)
                if (leaf[c]==1) findmax(c,nows+(sum[s]-sum[c])); else findmax(c,nows+(sum[s]-sum[c]-1));
        }
    }
}

void calc(int s)
{
    hash[s]=1;
    int c,nt=0;
    for (int i=0;i<f[s].size();i++)
    {
        c=f[s][i];
        if (hash[c]==0)
        {
            nt=1;
            calc(c);
            if (leaf[c]==0) sum[s]+=sum[c]+1;
        }
    }
    if (nt==0) leaf[s]=1;
}

int main()
{
    //freopen("F.in","r",stdin);

    scanf("%d %d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d %d",&xc,&yc);
        a[xc].p_b(yc);
        a[yc].p_b(xc);
    }
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(big,0,sizeof(big));
    ans=n;
    for (int i=1;i<=n;i++)
        if (dfn[i]==0)
        {
            o=0;
            top=0;
            tot=0;
            memset(where,0,sizeof(where));
            dfs(i,0);
            ans-=tot;
            for (int j=1;j<=n;j++) f[j].clear();
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                    for (int ck=0;ck<a[j].size();ck++)
                    {
                        k=a[j][ck];
                        if ((where[k]!=0)&&(where[j]!=where[k]))
                        {
                            if (big[where[j]][where[k]]==i) continue;
                            big[where[j]][where[k]]=i;
                            big[where[k]][where[j]]=i;
                            f[where[j]].p_b(where[k]);
                            f[where[k]].p_b(where[j]);
                        }
                    }
            //for (int j=1;j<=n;j++) cout<<where[j]<<" ";cout<<endl;
            nowans=maxlongint;
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                {
                    memset(hash,0,sizeof(hash));
                    memset(sum,0,sizeof(sum));
                    memset(leaf,0,sizeof(leaf));
                    calc(where[j]);
                    memset(hash,0,sizeof(hash));
                    findmax(where[j],0);
                }
            //cout<<nowans<<endl;
            ans+=nowans;
        }
    cout<<ans<<endl;

    return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <set>
#include <algorithm>
#include <map>
#include <bitset>
#include <vector>
#include <queue>
#include <utility>
#include <functional>
#include <sstream>
#include <list>
#include <complex>

#define maxlongint 2147483647
#define biglongint 2139062143
#define LL long long
#define ULL unsigned long long
#define p_b push_back
#define m_p make_pair
#define l_b lower_bound

using namespace std;

typedef pair<int,int> PII;
typedef pair<pair<int,int>,int> PIII;

const int maxn=2005;
vector<int> a[maxn],f[maxn];
int dfn[maxn],low[maxn],where[maxn],hash[maxn],stack[maxn],big[maxn][maxn],leaf[maxn],sum[maxn];
int n,m,k,xc,yc,ans,nowans,tot,o,top;

void dfs(int s,int fa)
{
    int c;
    ++o;
    dfn[s]=o;
    low[s]=o;
    ++top;
    stack[top]=s;
    for (int i=0;i<a[s].size();i++)
    {
        c=a[s][i];
        if (c==fa) continue;
        if (dfn[c]==0)
        {
            dfs(c,s);
            low[s]=min(low[s],low[c]);
        }
        else
            low[s]=min(low[s],dfn[c]);
    }
    if (dfn[s]==low[s])
    {
        ++tot;
        while (stack[top+1]!=s)
        {
            where[stack[top]]=tot;
            low[stack[top]]=maxlongint;
            dfn[stack[top]]=maxlongint;
            --top;
        }
    }
}

void findmax(int s,int nows)
{
    int c;
    hash[s]=1;
    //cout<<s<<" "<<nows<<endl;
    if (leaf[s]==1)
    {
        nowans=min(nowans,nows);
    }
    else
    {
        for (int i=0;i<f[s].size();i++)
        {
            c=f[s][i];
            if (hash[c]==0)
                if (leaf[c]==1) findmax(c,nows+(sum[s]-sum[c])); else findmax(c,nows+(sum[s]-sum[c]-1));
        }
    }
}

void calc(int s)
{
    hash[s]=1;
    int c,nt=0;
    for (int i=0;i<f[s].size();i++)
    {
        c=f[s][i];
        if (hash[c]==0)
        {
            nt=1;
            calc(c);
            if (leaf[c]==0) sum[s]+=sum[c]+1;
        }
    }
    if (nt==0) leaf[s]=1;
}

int main()
{
    freopen("F.in","r",stdin);

    scanf("%d %d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d %d",&xc,&yc);
        a[xc].p_b(yc);
        a[yc].p_b(xc);
    }
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(big,0,sizeof(big));
    ans=n;
    for (int i=1;i<=n;i++)
        if (dfn[i]==0)
        {
            o=0;
            top=0;
            tot=0;
            memset(where,0,sizeof(where));
            dfs(i,0);
            ans-=tot;
            for (int j=1;j<=n;j++) f[j].clear();
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                    for (int ck=0;ck<a[j].size();ck++)
                    {
                        k=a[j][ck];
                        if ((where[k]!=0)&&(where[j]!=where[k]))
                        {
                            if (big[where[j]][where[k]]==i) continue;
                            big[where[j]][where[k]]=i;
                            big[where[k]][where[j]]=i;
                            f[where[j]].p_b(where[k]);
                            f[where[k]].p_b(where[j]);
                        }
                    }
            //for (int j=1;j<=n;j++) cout<<where[j]<<" ";cout<<endl;
            nowans=maxlongint;
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                {
                    memset(hash,0,sizeof(hash));
                    memset(sum,0,sizeof(sum));
                    memset(leaf,0,sizeof(leaf));
                    calc(where[j]);
                    memset(hash,0,sizeof(hash));
                    findmax(where[j],0);
                }
            //cout<<nowans<<endl;
            ans+=nowans;
        }
    cout<<ans<<endl;

    return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <set>
#include <algorithm>
#include <map>
#include <bitset>
#include <vector>
#include <queue>
#include <utility>
#include <functional>
#include <sstream>
#include <list>
#include <complex>

#define maxlongint 2147483647
#define biglongint 2139062143
#define LL long long
#define ULL unsigned long long
#define p_b push_back
#define m_p make_pair
#define l_b lower_bound

using namespace std;

typedef pair<int,int> PII;
typedef pair<pair<int,int>,int> PIII;

const int maxn=2005;
vector<int> a[maxn],f[maxn];
int dfn[maxn],low[maxn],where[maxn],hash[maxn],stack[maxn],big[maxn][maxn],leaf[maxn],sum[maxn];
int n,m,k,xc,yc,ans,nowans,tot,o,top;

void dfs(int s,int fa)
{
    int c;
    ++o;
    dfn[s]=o;
    low[s]=o;
    ++top;
    stack[top]=s;
    for (int i=0;i<a[s].size();i++)
    {
        c=a[s][i];
        if (c==fa) continue;
        if (dfn[c]==0)
        {
            dfs(c,s);
            low[s]=min(low[s],low[c]);
        }
        else
            low[s]=min(low[s],dfn[c]);
    }
    if (dfn[s]==low[s])
    {
        ++tot;
        while (stack[top+1]!=s)
        {
            where[stack[top]]=tot;
            low[stack[top]]=maxlongint;
            dfn[stack[top]]=maxlongint;
            --top;
        }
    }
}

void findmax(int s,int nows)
{
    int c;
    hash[s]=1;
    //cout<<s<<" "<<nows<<endl;
    if (leaf[s]==1)
    {
        nowans=min(nowans,nows);
    }
    else
    {
        for (int i=0;i<f[s].size();i++)
        {
            c=f[s][i];
            if (hash[c]==0)
                if (leaf[c]==1) findmax(c,nows+(sum[s]-sum[c])); else findmax(c,nows+(sum[s]-sum[c]-1));
        }
    }
}

void calc(int s)
{
    hash[s]=1;
    int c,nt=0;
    for (int i=0;i<f[s].size();i++)
    {
        c=f[s][i];
        if (hash[c]==0)
        {
            nt=1;
            calc(c);
            if (leaf[c]==0) sum[s]+=sum[c]+1;
        }
    }
    if (nt==0) leaf[s]=1;
}

int main()
{
    //freopen("F.in","r",stdin);

    scanf("%d %d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d %d",&xc,&yc);
        a[xc].p_b(yc);
        a[yc].p_b(xc);
    }
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(big,0,sizeof(big));
    ans=n-1;
    for (int i=1;i<=n;i++)
        if (dfn[i]==0)
        {
            o=0;
            top=0;
            tot=0;
            memset(where,0,sizeof(where));
            dfs(i,0);
            ans-=tot;
            for (int j=1;j<=n;j++) f[j].clear();
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                    for (int ck=0;ck<a[j].size();ck++)
                    {
                        k=a[j][ck];
                        if ((where[k]!=0)&&(where[j]!=where[k]))
                        {
                            if (big[where[j]][where[k]]==i) continue;
                            big[where[j]][where[k]]=i;
                            big[where[k]][where[j]]=i;
                            f[where[j]].p_b(where[k]);
                            f[where[k]].p_b(where[j]);
                        }
                    }
            //for (int j=1;j<=n;j++) cout<<where[j]<<" ";cout<<endl;
            nowans=maxlongint;
            for (int j=1;j<=n;j++)
                if (where[j]!=0)
                {
                    memset(hash,0,sizeof(hash));
                    memset(sum,0,sizeof(sum));
                    memset(leaf,0,sizeof(leaf));
                    calc(where[j]);
                    memset(hash,0,sizeof(hash));
                    findmax(where[j],0);
                }
            //cout<<nowans<<endl;
            ans+=nowans+1;
        }
    cout<<ans<<endl;

    return 0;
}


/*
    Problem:
    Algorithm:
    Note:
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<string>
#include<iomanip>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

#define rep(i,x,y) for(i=x;i<=y;i++)
#define _rep(i,x,y) for(i=x;i>=y;i--)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
#define sqr(x) ((x)*(x))
#define mp make_pair
#define fi first
#define se second
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)

typedef long long ll;
typedef long double real;
void read(int&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;}

const int N=2010;
const int M=2000010;
const int inf=1000000000;
int n,m,i,j,k,l,p,x,y,cnt,res,ans;

int edge,e[M],b[M],fir[N],last[N];
void clear(){edge=0;CL(b,-1);CL(fir,-1);}
void add(int x,int y){e[edge]=y;if(fir[x]==-1)fir[x]=edge;else b[last[x]]=edge;last[x]=edge++;}
int dfn[N],low[N],st[N],col[N],size[N],ti,co;
void dfs(int i,int f)
{
	dfn[i]=low[i]=++ti;st[++st[0]]=i;
	for(int k=fir[i];k>=0;k=b[k])if(e[k]!=f)
	if(!dfn[e[k]])dfs(e[k],i),upmin(low[i],low[e[k]]);
	else if(!col[e[k]])upmin(low[i],dfn[e[k]]);
	if(dfn[i]==low[i]){++co;while(st[st[0]+1]!=i)col[st[st[0]--]]=co,size[co]++;cnt+=size[co]-1;}
}

int g[N][N];bool G[N][N];bool vis[N];

int q[N],fa[N],ch[N],leaf[N];

void go(int i,int t)
{
	int k;

	rep(k,1,g[i][0])if(g[i][k]!=fa[i])t+=size[g[i][k]]-leaf[g[i][k]];
	upmin(res,t);

	rep(k,1,g[i][0])if(g[i][k]!=fa[i])
	go(g[i][k],t-(size[g[i][k]]-leaf[g[i][k]]));
}
void bfs(int s)
{
	int i,j,k,u;
	CL(fa,0);q[1]=s;CL(size,0);CL(ch,0);CL(leaf,0);
	for(i=j=1;i<=j;i++)
	{
		u=q[i];
		rep(k,1,g[u][0])if(g[u][k]!=fa[u])
		ch[u]++,fa[g[u][k]]=u,q[++j]=g[u][k];
	}
	_rep(i,j,1)
	{
		u=q[i];size[u]++;
		if(ch[u]==0)leaf[u]++;
		leaf[fa[u]]+=leaf[u];
		size[fa[u]]+=size[u];
	}

	go(s,0);
}

void work(int i)
{
	st[++st[0]]=i;vis[i]=1;
	int k;rep(k,1,g[i][0])if(!vis[g[i][k]])work(g[i][k]);
}
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    read(n);read(m);
    clear();rep(i,1,m)read(x),read(y),add(x,y),add(y,x);;

    cnt=0;rep(i,1,n)if(!dfn[i])dfs(i,0),cnt++;cnt--;

    rep(i,1,n)
    {
		for(k=fir[i];k>=0;k=b[k])
		if(col[i]!=col[e[k]]&&(!G[col[i]][col[e[k]]]))
		{
			x=col[i];y=col[e[k]];
			g[x][++g[x][0]]=y;
			g[y][++g[y][0]]=x;
			G[x][y]=G[y][x]=1;
		}
	}

    ans=cnt;
    rep(i,1,co)if(!vis[i])
    {
		st[0]=0;work(i);
		res=inf;rep(j,1,st[0])bfs(st[j]);
		ans+=res;
	}

    printf("%d\n",ans);

    scanf("\n");
    return 0;
}


/*
    Problem:
    Algorithm:
    Note:
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<string>
#include<iomanip>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

#define rep(i,x,y) for(i=x;i<=y;i++)
#define _rep(i,x,y) for(i=x;i>=y;i--)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
#define sqr(x) ((x)*(x))
#define mp make_pair
#define fi first
#define se second
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)

typedef long long ll;
typedef long double real;
void read(int&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;}

const int N=2010;
const int M=2000010;
const int inf=1000000000;
int n,m,i,j,k,l,p,x,y,cnt,res,ans;

int edge,e[M],b[M],fir[N],last[N];
void clear(){edge=0;CL(b,-1);CL(fir,-1);}
void add(int x,int y){e[edge]=y;if(fir[x]==-1)fir[x]=edge;else b[last[x]]=edge;last[x]=edge++;}
int dfn[N],low[N],st[N],col[N],size[N],ti,co;
void dfs(int i,int f)
{
	dfn[i]=low[i]=++ti;st[++st[0]]=i;
	for(int k=fir[i];k>=0;k=b[k])if(e[k]!=f)
	if(!dfn[e[k]])dfs(e[k],i),upmin(low[i],low[e[k]]);
	else if(!col[e[k]])upmin(low[i],dfn[e[k]]);
	if(dfn[i]==low[i]){++co;while(st[st[0]+1]!=i)col[st[st[0]--]]=co,size[co]++;cnt+=size[co]-1;}
}

int g[N][N];bool G[N][N];bool vis[N];

int q[N],sum[N],fa[N],ch[N];

void go(int i,int t)
{
	int k;
	t+=sum[i]-ch[i];upmin(res,t);
	rep(k,1,g[i][0])if(g[i][k]!=fa[i])
	go(g[i][k],t-(sum[g[i][k]]));
}
void bfs(int s)
{
	int i,j,k,u;
	CL(fa,0);q[1]=s;CL(sum,0);CL(ch,0);
	for(i=j=1;i<=j;i++)
	{
		u=q[i];
		rep(k,1,g[u][0])if(g[u][k]!=fa[u])
		ch[u]++,fa[g[u][k]]=u,q[++j]=g[u][k];
	}
	_rep(i,j,1){u=q[i];sum[u]++;if(fa[u])sum[fa[u]]+=sum[u];}
	rep(i,1,j)sum[q[i]]--;

	go(s,0);
}

void work(int i)
{
	st[++st[0]]=i;vis[i]=1;
	int k;rep(k,1,g[i][0])if(!vis[g[i][k]])work(g[i][k]);
}
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    read(n);read(m);
    clear();rep(i,1,m)read(x),read(y),add(x,y),add(y,x);;

    cnt=0;rep(i,1,n)if(!dfn[i])dfs(i,0),cnt++;cnt--;

    rep(i,1,n)
    {
		for(k=fir[i];k>=0;k=b[k])
		if(col[i]!=col[e[k]]&&(!G[col[i]][col[e[k]]]))
		{
			x=col[i];y=col[e[k]];
			g[x][++g[x][0]]=y;
			g[y][++g[y][0]]=x;
			G[x][y]=G[y][x]=1;
		}
	}

    ans=cnt;
    rep(i,1,co)if(!vis[i])
    {
		st[0]=0;work(i);
		res=inf;rep(j,1,st[0])bfs(st[j]);
		ans+=res;
	}

    printf("%d\n",ans);

    scanf("\n");
    return 0;
}


#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cfloat>
#include <numeric>

using namespace std;

const int oo = 0x3f3f3f3f;
const double eps = 1e-9;

typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;

#define sz(c) int((c).size())
#define all(c) (c).begin(), (c).end()
#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define FORD(i,a,b) for (int i = int(b)-1; i >= (a); i--)
#define FORIT(i,c) for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); i++)

int N, M, minr[2100], dep[2100], dist[2100], res, nxt;
stack<pii> st;
vi adj[2100], adj2[2100];

int dfs(int n, int p, int d) {
	dep[n] = minr[n] = d;
	st.push(pii(n, 0));
	FOR(i, 0, sz(adj[n])) {
		int m = adj[n][i];
		if (m == p) continue;
		if (dep[m] == -1) {
			int dd = dfs(m, n, d+1);
			minr[n] = min(minr[n], dd);
			if (dd == dep[m]) {
				res--;
				while (1) {
					pii p = st.top();
					st.pop();
					if (p.second == 0) {
						res++;
					} else {
						adj2[nxt].push_back(p.first);
						adj2[p.first].push_back(nxt);
					}
					if (p.first == m && p.second == 0) break;
				}
				st.push(pii(nxt++, 1));
			}
		} else {
			minr[n] = min(minr[n], dep[m]);
		}
	}
	return minr[n];
}

void bfs(int n) {
	FOR(i, 0, nxt) dist[i] = oo;
	dist[n] = 0;
	queue<int> q;
	q.push(n);
	while (!q.empty()) {
		n = q.front();
		q.pop();
		FOR(i, 0, sz(adj2[n])) {
			int m = adj2[n][i];
			if (dist[m] < oo) continue;
			dist[m] = dist[n] + 1;
			q.push(m);
		}
	}
}

int main() {
	scanf("%d%d", &N, &M);
	FOR(i, 0, M) {
		int a, b;
		scanf("%d%d", &a, &b);
		adj[a-1].push_back(b-1);
		adj[b-1].push_back(a-1);
	}
	res = -1;
	memset(dep, -1, sizeof(dep));
	FOR(i, 0, N) {
		if (dep[i] == -1) {
			res++;
			adj[N].clear();
			adj[N].push_back(i);
			while (!st.empty()) st.pop();
			nxt = 0;
			dfs(N, -1, 0);
			if (nxt == 1) continue;
			bfs(0);
			int imax = 0;
			FOR(j, 1, nxt) if (dist[j] > dist[imax]) imax = j;
			bfs(imax);
			imax = 0;
			FOR(j, 1, nxt) if (dist[j] > dist[imax]) imax = j;
			res += (nxt - dist[imax] + 1);
			FOR(j, 0, nxt) if (sz(adj2[j]) == 1) res--;
			FOR(j, 0, nxt) adj2[j].clear();
		}
	}
	printf("%d\n", res);
	return 0;
}


#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cfloat>
#include <numeric>

using namespace std;

const int oo = 0x3f3f3f3f;
const double eps = 1e-9;

typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;

#define sz(c) int((c).size())
#define all(c) (c).begin(), (c).end()
#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define FORD(i,a,b) for (int i = int(b)-1; i >= (a); i--)
#define FORIT(i,c) for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); i++)

int N, M, minr[2100], dep[2100], tab[2100], res, nxt, best;
stack<pii> st;
vi adj[2100], adj2[2100];

int dfs(int n, int p, int d) {
	dep[n] = minr[n] = d;
	st.push(pii(n, 0));
	FOR(i, 0, sz(adj[n])) {
		int m = adj[n][i];
		if (m == p) continue;
		if (dep[m] == -1) {
			int dd = dfs(m, n, d+1);
			minr[n] = min(minr[n], dd);
			if (dd == dep[m]) {
				res--;
				while (1) {
					pii p = st.top();
					st.pop();
					if (p.second == 0) {
						res++;
					} else {
						adj2[nxt].push_back(p.first);
						adj2[p.first].push_back(nxt);
					}
					if (p.first == m && p.second == 0) break;
				}
				st.push(pii(nxt++, 1));
			}
		} else {
			minr[n] = min(minr[n], dep[m]);
		}
	}
	return minr[n];
}

int rek(int n, int p) {
	tab[n] = sz(adj2[n]) + 1;
	int m1 = -1, m2 = -1;
	FOR(i, 0, sz(adj2[n])) {
		int m = adj2[n][i];
		if (m == p) continue;
		rek(m, n);
		tab[n] = max(tab[n], tab[m] + sz(adj2[n]) - 1);
		if (m1 == -1) {
			m1 = tab[m];
		} else if (m2 == -1) {
			m2 = tab[m];
		} else {
			m2 = max(m2, tab[m]);
		}
		if (m1 < m2) swap(m1, m2);
	}
	best = max(best, tab[n]);
	if (m2 != -1) best = max(best, m1 + m2 + sz(adj2[n]) - 3);
	return tab[n];
}

int main() {
	scanf("%d%d", &N, &M);
	FOR(i, 0, M) {
		int a, b;
		scanf("%d%d", &a, &b);
		adj[a-1].push_back(b-1);
		adj[b-1].push_back(a-1);
	}
	res = -1;
	memset(dep, -1, sizeof(dep));
	FOR(i, 0, N) {
		if (dep[i] == -1) {
			res++;
			adj[N].clear();
			adj[N].push_back(i);
			while (!st.empty()) st.pop();
			nxt = 0;
			dfs(N, -1, 0);
			best = 0;
			rek(0, -1);
			res += (nxt - best);
			FOR(j, 0, nxt) adj2[j].clear();
		}
	}
	printf("%d\n", res);
	return 0;
}


#include<cstdio>
using namespace std;
int n,m,i,x,y,vis[2010],lab[2010],v[200010],ne[200010],head[200010],num,top,stack[2010],low[2010],tim[2010];
int gs[2010],dgs,ne1[2010],head1[2010],l,time,ans,use[2010],zgs[2010],zs[2010],dad[2010],aa[2010],max1,sg,root;
void add(int x,int y){v[++l]=y;ne[l]=head[x];head[x]=l;}
void dfs(int x,int pre)
{
    vis[x]=num;tim[x]=low[x]=++time;stack[++top]=x;
    for(int i=head[x];i;i=ne[i])
    if(v[i]!=pre)
    {

        if(!vis[v[i]])dfs(v[i],x);
        if(low[v[i]]<low[x])low[x]=low[v[i]];
    }if(low[x]==tim[x])
    {
        dgs++;gs[vis[x]]++;
        for(;stack[top+1]!=x;top--)
        {
            lab[stack[top]]=dgs;
            ne1[stack[top]]=head1[dgs];
            head1[dgs]=stack[top];ans++;
        }ans--;
    }
}
void dfs1(int x)
{
    use[x]=1;int m1=0,m2=0;//printf("dfs1:%d\n",x);
    for(int i=head1[x];i;i=ne1[i])
        for(int j=head[i];j;j=ne[j])
            if(!use[lab[v[j]]])
            {
                dad[lab[v[j]]]=x;
                dfs1(lab[v[j]]),zs[x]++;zgs[x]+=zgs[lab[v[j]]];
                if(aa[lab[v[j]]]>m1)m2=m1,m1=aa[lab[v[j]]];else
                if(aa[lab[v[j]]]>m2)m2=aa[lab[v[j]]];
            }if(!m2)m2=1;if(!m1)m1=1;aa[x]=m1+zs[x];
    //printf("%d %d %d %d %d\n",x,m1,m2,zs[x],dad[x]);
    if(m1+m2+zs[x]-1>max1)max1=m1+m2+zs[x]-(x==root);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    for(i=1;i<=n;i++)if(!vis[i])num++,dfs(i,0),ans++;ans--;
    for(i=1;i<=n;i++)if(vis[i]>sg){max1=0;root=lab[i];dfs1(lab[i]);sg=vis[i];ans+=gs[vis[i]]-max1;}
    printf("%d\n",ans);
}


#include<cstdio>
using namespace std;
int n,m,i,x,y,vis[2010],lab[2010],v[200010],ne[200010],head[200010],num,top,stack[2010],low[2010],tim[2010];
int gs[2010],dgs,ne1[2010],head1[2010],l,time,ans,use[2010],zgs[2010],zs[2010],dad[2010],aa[2010],max1,sg,root,kuse[2010],bb[2010];
void add(int x,int y){v[++l]=y;ne[l]=head[x];head[x]=l;}
void dfs(int x,int pre)
{
    vis[x]=num;tim[x]=low[x]=++time;stack[++top]=x;
    for(int i=head[x];i;i=ne[i])
    if(v[i]!=pre)
    {

        if(!vis[v[i]])dfs(v[i],x);
        if(low[v[i]]<low[x])low[x]=low[v[i]];
    }if(low[x]==tim[x])
    {
        dgs++;gs[vis[x]]++;
        for(;stack[top+1]!=x;top--)
        {
            lab[stack[top]]=dgs;
            ne1[stack[top]]=head1[dgs];
            head1[dgs]=stack[top];ans++;
        }ans--;
    }
}
void dfs1(int x)
{
    if(!use[x])
    {
        use[x]=1;
        for(int i=head1[x];i;i=ne1[i])
            for(int j=head[i];j;j=ne[j])
                if(!use[lab[v[j]]])
                {
                    dad[lab[v[j]]]=x;dfs1(lab[v[j]]);
                    aa[x]+=aa[lab[v[j]]]+1;bb[x]+=bb[lab[v[j]]];
                }if(!aa[x]&&x!=root)bb[x]=1;if(x!=root)return;
    }if(x!=root)zgs[x]=zgs[dad[x]]+aa[dad[x]]-bb[dad[x]]-aa[x]+bb[x]-((bb[dad[x]]-bb[x]==0)&&dad[x]==root);
    int m1=0,m2=0;kuse[x]=1;
    for(int i=head1[x];i;i=ne1[i])
        for(int j=head[i];j;j=ne[j])
            if(!kuse[lab[v[j]]])
            {
                dfs1(lab[v[j]]);
                if(zs[lab[v[j]]]>=m1)m2=m1,m1=zs[lab[v[j]]]+1;
                else if(zs[lab[v[j]]]>=m2)m2=zs[lab[v[j]]]+1;
            }zs[x]=m1;if(zs[x]>aa[x]-bb[x])zs[x]=aa[x]-bb[x];
    if(zgs[x]+aa[x]-bb[x]-m1-m2<max1&&aa[x]>=bb[x])max1=zgs[x]+aa[x]-bb[x]-m1-m2;
    if(zgs[x]<max1&&aa[x]<bb[x])max1=zgs[x];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    for(i=1;i<=n;i++)if(!vis[i])num++,dfs(i,0),ans++;ans--;
    for(i=1;i<=n;i++)if(vis[i]>sg){max1=gs[vis[i]];root=lab[i];dfs1(lab[i]);sg=vis[i];ans+=max1;}
    printf("%d\n",ans);
}


#include<cstdio>
using namespace std;
int n,m,i,x,y,vis[2010],lab[2010],v[200010],ne[200010],head[200010],num,top,stack[2010],low[2010],tim[2010];
int gs[2010],dgs,ne1[2010],head1[2010],l,time,ans,use[2010],zgs[2010],zs[2010],dad[2010],aa[2010],max1,sg;
void add(int x,int y){v[++l]=y;ne[l]=head[x];head[x]=l;}
void dfs(int x,int pre)
{
	vis[x]=num;tim[x]=low[x]=++time;stack[++top]=x;
	for(int i=head[x];i;i=ne[i])
	if(v[i]!=pre)
	{

		if(!vis[v[i]])dfs(v[i],x);
		if(low[v[i]]<low[x])low[x]=low[v[i]];
	}if(low[x]==tim[x])
	{
		dgs++;gs[vis[x]]++;
		for(;stack[top+1]!=x;top--)
		{
			lab[stack[top]]=dgs;
			ne1[stack[top]]=head1[dgs];
			head1[dgs]=stack[top];ans++;
		}ans--;
	}
}
void dfs1(int x)
{
	use[x]=1;int m1=0,m2=0;//printf("dfs1:%d\n",x);
	for(int i=head1[x];i;i=ne1[i])
		for(int j=head[i];j;j=ne[j])
			if(!use[lab[v[j]]])
			{
				dad[lab[v[j]]]=x;
				dfs1(lab[v[j]]),zs[x]++;zgs[x]+=zgs[lab[v[j]]];
				if(aa[lab[v[j]]]>m1)m2=m1,m1=aa[lab[v[j]]];else
				if(aa[lab[v[j]]]>m2)m2=aa[lab[v[j]]];
			}if(!m2)m2=1;if(!m1)m1=1;aa[x]=m1+zs[x];
	//printf("%d %d %d %d %d\n",x,m1,m2,zs[x],dad[x]);
	if(m1+m2+zs[x]-1>max1)max1=m1+m2+zs[x]-1;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(i=1;i<=n;i++)if(!vis[i])num++,dfs(i,0),ans++;ans--;
	for(i=1;i<=n;i++)if(vis[i]>sg){max1=0;dfs1(lab[i]);sg=vis[i];ans+=gs[vis[i]]-max1;}
	printf("%d\n",ans);
}


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
const int mn=2012;
vector<int> e[mn],g[mn];
int ans,n,m,scc,cnt,lst,top;
int dfn[mn],stk[mn],col[mn];
int tarjan(int fa,int x){
    if(dfn[x])return dfn[x];
    int low=dfn[x]=cnt++;
    stk[++top]=x;
    for(int i=0;i<e[x].size();i++)
        if(e[x][i]!=fa)low=min(low,tarjan(x,e[x][i]));
    if(dfn[x]==low){
        for(scc++;;){
            col[stk[top]]=scc;
            if(stk[top--]==x)break;
        }
    }
    return low;
}
int dfs(int fa,int x){
    dfn[x]=1;
    int p=0,q=0;
    if(g[x].size()<2)cnt++;
    for(int i=0;i<g[x].size();i++)
        if(g[x][i]!=fa){
            int tmp=dfs(x,g[x][i]);
            if(tmp>=p){
                q=p;
                p=tmp;
            }
            else if(tmp>q)q=tmp;
        }
    lst=max(lst,p+q+1);
    return p+1;
}
int main(){
    //freopen("AC.in","r",stdin);
    //freopen("AC.out","w",stdout);
    scanf("%d%d",&n,&m);
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].pb(y);
        e[y].pb(y);
    }
    for(int i=1;i<=n;i++)tarjan(0,i);
    for(int i=1;i<=n;i++)
        for(int j=0;j<e[i].size();j++)
            if(col[i]!=col[e[i][j]])g[i].pb(col[e[i][j]]);
    memset(dfn,0,sizeof dfn);
    bool f=0;
    for(int i=1;i<=scc;i++)
        if(!dfn[i]){
            cnt=lst=0;
            dfs(0,i);
            if(cnt==1)ans+=1;
            else ans+=lst+cnt-2;
            ans-=f;
            f=1;
        }
    cout<<n-ans;
    return 0;
}