#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(x);
    }
    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[col[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;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 2005, maxm = 1e5 + 20, nya = -1;

struct Edge
{
    int v, next;
    Edge(int v = 0,int next = 0):v(v), next(next){}
}edge[maxm << 1];
int N, M, head[maxn], el;
int snum, set[maxn];
bool hash[maxn], leaf[maxn];

std::vector<int> G[maxn];
int tnum, root[maxn];

void newedge(int u,int v)
{
    edge[el] = Edge(v, head[u]), head[u] = el++;
}
void Tarjan(int a,int pre)
{
    static int dt = 0, low[maxn] = {0}, dfn[maxn] = {0}, stack[maxn] = {0}, top = 0;
    static bool flag[maxn] = {false};

    hash[a] = true;
    low[a] = dfn[a] = ++dt;
    stack[++top] = a, flag[a] = true;

    for(int i = head[a]; i != nya; i = edge[i].next)
    {
        if((i ^ 1) == pre) continue;
        int p = edge[i].v;

        if(!hash[p])
            Tarjan(p, i), low[a] = std::min(low[a], low[p]);
        else
            if(flag[p]) low[a] = std::min(low[a], dfn[p]);
    }

    if(low[a] == dfn[a])
    {
        ++snum;
        while(true)
        {
            int p = stack[top--];
            flag[p] = false;
            set[p] = snum;
            if(p == a) break;
        }
    }
}
void init()
{
    int u, v;
    read(N), read(M);

    for(int i = 1; i <= N; i++) head[i] = nya;
    for(int i = 1; i <= M; i++)
    {
        read(u), read(v);
        newedge(u, v), newedge(v, u);
    }
}
void rebuild()
{
    for(int i = 1; i <= N; i++)
        for(int j = head[i]; j != nya ; j = edge[j].next)
        {
            int v = set[edge[j].v];
            if(set[i] != v) G[set[i]].push_back(v);
        }
}
int dfs(int a)
{
    int ret = 0;

    if(G[a].size() != 1) ret = a;

    hash[a] = true;
    for(int i = 0; i < G[a].size(); i++)
        if(!hash[G[a][i]]) ret = std::max(dfs(G[a][i]), ret);

    return ret;
}
std::pair<int,int>path(int a,int fa)
{
    std::pair<int,int> ret = std::make_pair(0, a);
    if(leaf[a] || G[a].size() == 0) return ret;

    for(int i = 0; i < G[a].size(); i++)
        if(G[a][i] != fa) ret = std::max(ret, path(G[a][i], a));
    ret.first++;

    return ret;
}
void solve()
{
    int ans = 0;

    for(int i = 1; i <= snum; i++) hash[i] = false;
    for(int i = 1; i <= snum; i++)
        if(!hash[i]) root[++tnum] = dfs(i);

    ans = N + tnum - 1;
    for(int i = 1; i <= snum; i++)
        if(G[i].size() == 1) leaf[i] = true, ans--;

    for(int i = 1; i <= tnum; i++)
        if(root[i]) ans -= path(path(root[i], 0).second, 0).first;

    write(ans);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("mmc.in","r",stdin);
    freopen("mmc.out","w",stdout);
#endif
    init();

    for(int i = 1; i <= N; i++)
        if(!hash[i]) Tarjan(i, M << 1 | 1);

    rebuild();

    solve();

#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 2005, maxm = 1e5 + 20, nya = -1;

struct Edge
{
	int v, next;
	Edge(int v = 0,int next = 0):v(v), next(next){}
}edge[maxm << 1];
int N, M, head[maxn], el;
int snum, set[maxn];
bool hash[maxn], leaf[maxn];

std::vector<int> G[maxn];
int tnum, root[maxn];

void newedge(int u,int v)
{
	edge[el] = Edge(v, head[u]), head[u] = el++;
}
void Tarjan(int a,int pre)
{
	static int dt = 0, low[maxn] = {0}, dfn[maxn] = {0}, stack[maxn] = {0}, top = 0;
	static bool flag[maxn] = {false};

	hash[a] = true;
	low[a] = dfn[a] = ++dt;
	stack[++top] = a, flag[a] = true;

	for(int i = head[a]; i != nya; i = edge[i].next)
	{
		if((i ^ 1) == pre) continue;
		int p = edge[i].v;

		if(!hash[p])
			Tarjan(p, i), low[a] = std::min(low[a], low[p]);
		else
			if(flag[p]) low[a] = std::min(low[a], dfn[p]);
	}

	if(low[a] == dfn[a])
	{
		++snum;
		while(true)
		{
			int p = stack[top--];
			flag[p] = false;
			set[p] = snum;
			if(p == a) break;
		}
	}
}
void init()
{
	int u, v;
	read(N), read(M);

	for(int i = 1; i <= N; i++) head[i] = nya;
	for(int i = 1; i <= M; i++)
	{
		read(u), read(v);
		newedge(u, v), newedge(v, u);
	}
}
void rebuild()
{
	for(int i = 1; i <= N; i++)
		for(int j = head[i]; j != nya ; j = edge[j].next)
		{
			int v = set[edge[j].v];
			if(set[i] != v) G[set[i]].push_back(v);
		}
}
int dfs(int a)
{
	int ret = 0;

	if(G[a].size() != 1) ret = a;

	hash[a] = true;
	for(int i = 0; i < G[a].size(); i++)
		if(!hash[G[a][i]]) ret = std::max(dfs(G[a][i]), ret);

	return ret;
}
std::pair<int,int>path(int a,int fa)
{
	std::pair<int,int> ret = std::make_pair(0, a);
	if(leaf[a] || G[a].size() == 0) return ret;

	for(int i = 0; i < G[a].size(); i++)
		if(G[a][i] != fa) ret = std::max(ret, path(G[a][i], a));
	ret.first++;

	return ret;
}
void solve()
{
	int ans = 0;

	for(int i = 1; i <= snum; i++) hash[i] = false;
	for(int i = 1; i <= snum; i++)
		if(!hash[i]) root[++tnum] = dfs(i);

	ans = N + tnum - 1;
	for(int i = 1; i <= snum; i++)
		if(G[i].size() <= 1) leaf[i] = true, ans--;

	for(int i = 1; i <= tnum; i++)
		if(root[i]) ans -= path(path(root[i], 0).second, 0).first;

	write(ans);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("mmc.in","r",stdin);
	freopen("mmc.out","w",stdout);
#endif
	init();

	for(int i = 1; i <= N; i++)
		if(!hash[i]) Tarjan(i, M << 1 | 1);

	rebuild();

	solve();

#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
#endif
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 2005, maxm = 1e5 + 20, nya = -1;

struct Edge
{
	int v, next;
	Edge(int v = 0,int next = 0):v(v), next(next){}
}edge[maxm << 1];
int N, M, head[maxn], el;
int snum, set[maxn];
bool hash[maxn], leaf[maxn];

std::vector<int> G[maxn];
int tnum, root[maxn];

void newedge(int u,int v)
{
	edge[el] = Edge(v, head[u]), head[u] = el++;
}
void Tarjan(int a,int pre)
{
	static int dt = 0, low[maxn] = {0}, dfn[maxn] = {0}, stack[maxn] = {0}, top = 0;
	static bool flag[maxn] = {false};

	hash[a] = true;
	low[a] = dfn[a] = ++dt;
	stack[++top] = a, flag[a] = true;

	for(int i = head[a]; i != nya; i = edge[i].next)
	{
		if((i ^ 1) == pre) continue;
		int p = edge[i].v;

		if(!hash[p])
			Tarjan(p, i), low[a] = std::min(low[a], low[p]);
		else
			if(flag[p]) low[a] = std::min(low[a], dfn[p]);
	}

	if(low[a] == dfn[a])
	{
		++snum;
		while(true)
		{
			int p = stack[top--];
			flag[p] = false;
			set[p] = snum;
			if(p == a) break;
		}
	}
}
void init()
{
	int u, v;
	read(N), read(M);

	for(int i = 1; i <= N; i++) head[i] = nya;
	for(int i = 1; i <= M; i++)
	{
		read(u), read(v);
		newedge(u, v), newedge(v, u);
	}
}
void rebuild()
{
	for(int i = 1; i <= N; i++)
		for(int j = head[i]; j != nya ; j = edge[j].next)
		{
			int v = set[edge[j].v];
			if(set[i] != v) G[set[i]].push_back(v);
		}
}
int dfs(int a)
{
	int ret = 0;

	if(G[a].size() != 1) ret = a;

	hash[a] = true;
	for(int i = 0; i < G[a].size(); i++)
		if(!hash[G[a][i]]) ret = std::max(dfs(G[a][i]), ret);

	return ret;
}
std::pair<int,int>path(int a,int fa)
{
	std::pair<int,int> ret = std::make_pair(0, a);
	if(leaf[a] || G[a].size() == 0) return ret;

	for(int i = 0; i < G[a].size(); i++)
		if(G[a][i] != fa) ret = std::max(ret, path(G[a][i], a));
	ret.first++;

	return ret;
}
void solve()
{
	int ans = 0;

	for(int i = 1; i <= snum; i++) hash[i] = false;
	for(int i = 1; i <= snum; i++)
		if(!hash[i]) root[++tnum] = dfs(i);

	ans = N + tnum - 1;
	for(int i = 1; i <= snum; i++)
		if(G[i].size() < 1) leaf[i] = true, ans--;

	for(int i = 1; i <= tnum; i++)
		if(root[i]) ans -= path(path(root[i], 0).second, 0).first;

	write(ans);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("mmc.in","r",stdin);
	freopen("mmc.out","w",stdout);
#endif
	init();

	for(int i = 1; i <= N; i++)
		if(!hash[i]) Tarjan(i, M << 1 | 1);

	rebuild();

	solve();

#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
#endif
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 2005, maxm = 1e5 + 20, nya = -1;

struct Edge
{
	int v, next;
	Edge(int v = 0,int next = 0):v(v), next(next){}
}edge[maxm << 1];
int N, M, head[maxn], el;
int snum, set[maxn];
bool hash[maxn], leaf[maxn];

std::vector<int> G[maxn];
int tnum, root[maxn];

void newedge(int u,int v)
{
	edge[el] = Edge(v, head[u]), head[u] = el++;
}
void Tarjan(int a,int pre)
{
	static int dt = 0, low[maxn] = {0}, dfn[maxn] = {0}, stack[maxn] = {0}, top = 0;
	static bool flag[maxn] = {false};

	hash[a] = true;
	low[a] = dfn[a] = ++dt;
	stack[++top] = a, flag[a] = true;

	for(int i = head[a]; i != nya; i = edge[i].next)
	{
		if((i ^ 1) == pre) continue;
		int p = edge[i].v;

		if(!hash[p])
			Tarjan(p, i), low[a] = std::min(low[a], low[p]);
		else
			if(flag[p]) low[a] = std::min(low[a], dfn[p]);
	}

	if(low[a] == dfn[a])
	{
		++snum;
		while(true)
		{
			int p = stack[top--];
			flag[p] = false;
			set[p] = snum;
			if(p == a) break;
		}
	}
}
void init()
{
	int u, v;
	read(N), read(M);

	for(int i = 1; i <= N; i++) head[i] = nya;
	for(int i = 1; i <= M; i++)
	{
		read(u), read(v);
		newedge(u, v), newedge(v, u);
	}
}
void rebuild()
{
	for(int i = 1; i <= N; i++)
		for(int j = head[i]; j != nya ; j = edge[j].next)
		{
			int v = set[edge[j].v];
			if(set[i] != v) G[set[i]].push_back(v);
		}
}
int dfs(int a)
{
	int ret = 0;

	if(G[a].size() > 1) ret = a;

	hash[a] = true;
	for(int i = 0; i < G[a].size(); i++)
		if(!hash[G[a][i]]) ret = std::max(dfs(G[a][i]), ret);

	return ret;
}
std::pair<int,int>path(int a,int fa)
{
	std::pair<int,int> ret = std::make_pair(0, a);

	for(int i = 0; i < G[a].size(); i++)
		if(G[a][i] != fa && !leaf[G[a][i]])
			ret = std::max(ret, path(G[a][i], a));
	ret.first++;

	return ret;
}
void solve()
{
	int ans = 0;

	for(int i = 1; i <= snum; i++) hash[i] = false;
	for(int i = 1; i <= snum; i++)
		if(!hash[i]) root[++tnum] = dfs(i);

	ans = N + tnum - 1;
	for(int i = 1; i <= snum; i++)
		if(G[i].size() <= 1) leaf[i] = true, ans--;

	for(int i = 1; i <= tnum; i++)
		if(root[i]) ans -= path(path(root[i], 0).second, 0).first;

	write(ans);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("mmc.in","r",stdin);
	freopen("mmc.out","w",stdout);
#endif
	init();

	for(int i = 1; i <= N; i++)
		if(!hash[i]) Tarjan(i, M << 1 | 1);

	rebuild();

	solve();

#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
#endif
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 2005, maxm = 1e5 + 20, nya = -1;

struct Edge
{
	int v, next;
	Edge(int v = 0,int next = 0):v(v), next(next){}
}edge[maxm << 1];
int N, M, head[maxn], el;
int snum, set[maxn];
bool hash[maxn], leaf[maxn];

std::vector<int> G[maxn];
int tnum, root[maxn];

void newedge(int u,int v)
{
	edge[el] = Edge(v, head[u]), head[u] = el++;
}
void Tarjan(int a,int pre)
{
	static int dt = 0, low[maxn] = {0}, dfn[maxn] = {0}, stack[maxn] = {0}, top = 0;
	static bool flag[maxn] = {false};

	hash[a] = true;
	low[a] = dfn[a] = ++dt;
	stack[++top] = a, flag[a] = true;

	for(int i = head[a]; i != nya; i = edge[i].next)
	{
		if((i ^ 1) == pre) continue;
		int p = edge[i].v;

		if(!hash[p])
			Tarjan(p, i), low[a] = std::min(low[a], low[p]);
		else
			if(flag[p]) low[a] = std::min(low[a], dfn[p]);
	}

	if(low[a] == dfn[a])
	{
		++snum;
		while(true)
		{
			int p = stack[top--];
			flag[p] = false;
			set[p] = snum;
			if(p == a) break;
		}
	}
}
void init()
{
	int u, v;
	read(N), read(M);

	for(int i = 1; i <= N; i++) head[i] = nya;
	for(int i = 1; i <= M; i++)
	{
		read(u), read(v);
		newedge(u, v), newedge(v, u);
	}
}
void rebuild()
{
	for(int i = 1; i <= N; i++)
		for(int j = head[i]; j != nya ; j = edge[j].next)
		{
			int v = set[edge[j].v];
			if(set[i] != v) G[set[i]].push_back(v);
		}
}
int dfs(int a)
{
	int ret = 0;

	if(G[a].size() != 1) ret = a;

	hash[a] = true;
	for(int i = 0; i < G[a].size(); i++)
		if(!hash[G[a][i]]) ret = std::max(dfs(G[a][i]), ret);

	return ret;
}
std::pair<int,int>path(int a,int fa)
{
	std::pair<int,int> ret = std::make_pair(0, a);

	for(int i = 0; i < G[a].size(); i++)
		if(G[a][i] != fa && !leaf[G[a][i]])
			ret = std::max(ret, path(G[a][i], a));
	ret.first++;

	return ret;
}
void solve()
{
	int ans = 0;

	for(int i = 1; i <= snum; i++) hash[i] = false;
	for(int i = 1; i <= snum; i++)
		if(!hash[i]) root[++tnum] = dfs(i);

	ans = N + tnum - 1;
	for(int i = 1; i <= snum; i++)
		if(G[i].size() <= 1) leaf[i] = true, ans--;

	for(int i = 1; i <= tnum; i++)
		if(root[i]) ans -= path(path(root[i], 0).second, 0).first;

	write(ans);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("mmc.in","r",stdin);
	freopen("mmc.out","w",stdout);
#endif
	init();

	for(int i = 1; i <= N; i++)
		if(!hash[i]) Tarjan(i, M << 1 | 1);

	rebuild();

	solve();

#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
#endif
	return 0;
}


#include<stdio.h>
#include<string.h>
# include<vector>
#include<algorithm>
using namespace std;
const int maxn=2010;
const int INF=maxn*100;
//vector<int> G[maxn],T[maxn];
int n,m;
bool vis[maxn];
bool f[maxn][maxn];
int dfn[maxn],low[maxn],dfs_clock,belong[maxn],cnt=0,size[maxn];
int S[maxn],top=-1;
int ans=0,res,node;

struct Graph{
	int first[maxn],to[maxn*maxn],edge,_next[maxn*maxn];
	Graph() {memset(first,-1,sizeof(first));edge=0;}

	void add(int a,int b) {_next[edge]=first[a];to[edge]=b;first[a]=edge++;}
}G,T;

void dfs(int x,int fa){
	dfn[x]=low[x]=++dfs_clock;S[++top]=x;
	//printf("x:%d\n",x);
	int v;
	for(int e=G.first[x];e!=-1;e=G._next[e]){
		v=G.to[e];
		if(v==fa) continue;
		if(!dfn[v]){
			dfs(v,x);
			low[x]=min(low[x],low[v]);
			if(low[v]==dfn[v]){//bridge
				//puts("fuck");
				int u=S[top--];cnt++;belong[u]=cnt;size[cnt]=1;
				while(S[top]!=x){
					u=S[top--];
					belong[u]=cnt;
					size[cnt]++;
				}
			}
		}
		else low[x]=min(low[x],dfn[v]);
	}
	//printf("dfn[%d]:%d low:%d\n",x,dfn[x],low[x]);
}
int dp[maxn][2],leave;

void Treedp(int x,int fa){
	vis[x]=1;node++;
	int v,son=0;
	dp[x][0]=-INF;dp[x][1]=-INF;
	for(int e=T.first[x];e!=-1;e=T._next[e]){
		v=T.to[e];
		if(v==fa) continue;son++;
		Treedp(v,x);
		if(dp[v][0]+1>=dp[x][0]){
			dp[x][1]=dp[x][0];
			dp[x][0]=dp[v][0]+1;
		}
		else if(dp[v][0]+1>dp[x][1])
			dp[x][1]=dp[v][0]+1;
	}
	if(dp[x][0]==-INF) //leave
		dp[x][0]=1;
	if(x==fa&&son<=1) leave++;
	if(x!=fa&&son==0) leave++;
	res=max(res,max(dp[x][0],dp[x][0]+dp[x][1]-1));
}

int main(){
	int a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a,&b);if(a==b) continue;
		G.add(a,b);G.add(b,a);
	}

	for(int i=1;i<=n;i++)
		if(!dfn[i]){
			dfs(i,i);
			if(top>=0){
				cnt++;size[cnt]=0;
				while(top>=0){
				size[cnt]++;belong[S[top--]]=cnt;
				}
			}
		}
	//for(int i=1;i<=n;i++) printf("belong[%d]:%d\n",i,belong[i]);
	for(int i=1;i<=cnt;i++) {f[i][i]=1,ans+=size[i]-1;}
	for(int i=1;i<=n;i++){
		for(int e=G.first[i];e!=-1;e=G._next[e]){
			if(!f[belong[i]][belong[G.to[e]]]){
				T.add(belong[i],belong[G.to[e]]);T.add(belong[G.to[e]],belong[i]);
				f[belong[i]][belong[G.to[e]]]=f[belong[G.to[e]]][belong[i]]=1;
			}
		}
	}

	int kuai=0;
	for(int i=1;i<=cnt;i++)
		if(!vis[i]){
			res=-INF;leave=0;node=0;
			Treedp(i,i);
			//printf("res:%d leave:%d \n",res,leave);
			ans+=node-res-leave+((res==1)?1:2);
			kuai++;
		}
	ans+=kuai-1;
	printf("%d\n",ans);
	return 0;
}
/*
9 11
1 2
2 3
1 3
3 4
4 5
5 6
5 7
6 7
7 9
7 8
8 9

*/


#include<stdio.h>
#include<string.h>
# include<vector>
#include<algorithm>
using namespace std;
const int maxn=2010;
const int INF=maxn*100;
const int maxm=200100;
//vector<int> G[maxn],T[maxn];
int n,m;
bool vis[maxn];
bool f[maxn][maxn];
int dfn[maxn],low[maxn],dfs_clock,belong[maxn],cnt=0,size[maxn];
int S[maxn],top=-1;
int ans=0,res,node;

struct Graph{
	int first[maxn],to[maxm],edge,_next[maxm];
	Graph() {memset(first,-1,sizeof(first));edge=0;}

	void add(int a,int b) {_next[edge]=first[a];to[edge]=b;first[a]=edge++;}
}G,T;

void dfs(int x,int fa){
	dfn[x]=low[x]=++dfs_clock;S[++top]=x;
	//printf("x:%d\n",x);
	int v;
	for(int e=G.first[x];e!=-1;e=G._next[e]){
		v=G.to[e];
		if(v==fa) continue;
		if(!dfn[v]){
			dfs(v,x);
			low[x]=min(low[x],low[v]);
			if(low[v]==dfn[v]){//bridge
				//puts("fuck");
				static int u;cnt++;size[cnt]=0;//printf("u:%d\n",u);
				while(S[top]!=v){
					u=S[top--];//printf("u:%d\n",u);
					belong[u]=cnt;
					size[cnt]++;
				}
				u=S[top--];//printf("u:%d\n",u);
					belong[u]=cnt;
					size[cnt]++;
			}
		}
		else low[x]=min(low[x],dfn[v]);
	}
	//printf("dfn[%d]:%d low:%d\n",x,dfn[x],low[x]);
}
int dp[maxn][2],leave;

void Treedp(int x,int fa){
	vis[x]=1;node++;//printf("x:%d\n",x);
	int v,son=0;
	dp[x][0]=-INF;dp[x][1]=-INF;
	for(int e=T.first[x];e!=-1;e=T._next[e]){
		v=T.to[e];
		if(v==fa) continue;son++;
		Treedp(v,x);
		if(dp[v][0]+1>=dp[x][0]){
			dp[x][1]=dp[x][0];
			dp[x][0]=dp[v][0]+1;
		}
		else if(dp[v][0]+1>dp[x][1])
			dp[x][1]=dp[v][0]+1;
	}
	if(dp[x][0]==-INF) //leave
		dp[x][0]=1;
	if(x==fa&&son<=1) leave++;
	if(x!=fa&&son==0) leave++;
	res=max(res,max(dp[x][0],dp[x][0]+dp[x][1]-1));
}

int main(){
	int a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a,&b);if(a==b) continue;
		G.add(a,b);G.add(b,a);
	}

	for(int i=1;i<=n;i++)
		if(!dfn[i]){
			dfs(i,i);
			if(top>=0){
				cnt++;size[cnt]=0;
				while(top>=0){
				size[cnt]++;belong[S[top--]]=cnt;
				}
			}
		}
//	for(int i=1;i<=n;i++) printf("belong[%d]:%d\n",i,belong[i]);
	for(int i=1;i<=cnt;i++) {f[i][i]=1,ans+=size[i]-1;}
	for(int i=1;i<=n;i++){
		for(int e=G.first[i];e!=-1;e=G._next[e]){
			if(!f[belong[i]][belong[G.to[e]]]){
				//printf("%d %d\n",belong[i],belong[G.to[e]]);
				T.add(belong[i],belong[G.to[e]]);T.add(belong[G.to[e]],belong[i]);
				f[belong[i]][belong[G.to[e]]]=f[belong[G.to[e]]][belong[i]]=1;
			}
		}
	}

	int kuai=0;
	for(int i=1;i<=cnt;i++)
		if(!vis[i]){
			//printf("i:%d\n",i);
			res=-INF;leave=0;node=0;
			Treedp(i,i);
			//printf("res:%d leave:%d \n",res,leave);
			ans+=node-res-leave+((res==1)?1:2);
			kuai++;
		}
	ans+=kuai-1;
	printf("%d\n",ans);
	return 0;
}
/*
9 11
1 2
2 3
1 3
3 4
4 5
5 6
5 7
6 7
7 9
7 8
8 9

*/


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=250010;
const int INF=~0U>>1;
typedef long long LL;
int n;
struct Stone{
	LL D,R;int m,p,bh;
	Stone() {}
	bool operator < (const Stone &rhs)const{
		return D<rhs.D;
	}
}stone[maxn];
int x,y;
int q[maxn],rear,D[maxn];
int ans=0;

struct SegmenTree{
	int _min[maxn<<2],p[maxn<<2],ans,anspos;

	void pushup(int o){
		if(_min[o<<1]<=_min[o<<1|1]) _min[o]=_min[o<<1],p[o]=p[o<<1];
			else  _min[o]=_min[o<<1|1],p[o]=p[o<<1|1];
	}

	void build(int o,int L,int R){
		if(L==R) { _min[o]=stone[L].m;p[o]=L;return;}
		int M=(L+R)>>1;
		build(o<<1,L,M);build(o<<1|1,M+1,R);
		pushup(o);
	}

	void update(int o,int L,int R,int pos,int val){
		if(L==R) {_min[o]=val;return;}
		int M=(L+R)>>1;
		if(pos<=M) update(o<<1,L,M,pos,val);
		else update(o<<1|1,M+1,R,pos,val);
		pushup(o);
	}

	void query(int o,int L,int R,int qL,int qR){
		if(qL<=L&&qR>=R){
			if(_min[o]<ans) ans=_min[o],anspos=p[o];
			return;
		}
		int M=(L+R)>>1;
		if(qL<=M) query(o<<1,L,M,qL,qR);
		if(qR>M) query(o<<1|1,M+1,R,qL,qR);
	}

	void query(int qL,int qR){
		ans=INF;
		query(1,1,n,qL,qR);
	}
}seg;

int main(){
	LL a,b;
	scanf("%d%d",&x,&y);scanf("%d%lld",&stone[1].p,&stone[1].R);
	stone[1].bh=0;
	stone[1].D=0;
	stone[1].m=INF;
	stone[1].R=stone[1].R*stone[1].R;
	scanf("%d",&n);n++;
	for(int i=2;i<=n;i++){
		scanf("%lld%lld%d%lld%d",&a,&b,&stone[i].p,&stone[i].R,&stone[i].m);
		stone[i].D=(LL)(a-x)*(a-x)+(LL)(b-y)*(b-y);
		stone[i].R=stone[i].R*stone[i].R;
		stone[i].bh=i;
	}
	sort(stone+1,stone+n+1);
	seg.build(1,1,n);

	for(int i=1;i<=n;i++){D[i]=stone[i].D; if(stone[i].bh==0) q[rear=0]=i;stone[i].bh=i;}

	for(int front=0;front<=rear;front++){
		int x=q[front];//printf("x:%d R:%lld m:%d p:%d D:%lld\n",x,stone[x].R,stone[x].m,stone[x].p,stone[x].D);
		int t=upper_bound(D+1,D+n+1,stone[x].R)-D-1;
		if(t>=1){
			while(1){
				seg.query(1,t);
				if(seg.ans<=stone[x].p){
					q[++rear]=seg.anspos;ans++;
					seg.update(1,1,n,seg.anspos,INF);
				}
				else break;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}


#include<stdio.h>
#include<string.h>
# include<vector>
#include<algorithm>
using namespace std;
const int maxn=2010;
const int INF=maxn*100;
vector<int> G[maxn],T[maxn];
int n,m;
bool vis[maxn];
bool f[maxn][maxn];
int dfn[maxn],low[maxn],dfs_clock,belong[maxn],cnt=0,size[maxn];
int S[maxn],top=-1;
int ans=0,res,node;

void dfs(int x,int fa){
	dfn[x]=low[x]=++dfs_clock;S[++top]=x;
	//printf("x:%d\n",x);
	int v;
	for(int e=0;e<G[x].size();e++){
		v=G[x][e];
		if(v==fa) continue;
		if(!dfn[v]){
			dfs(v,x);
			low[x]=min(low[x],low[v]);
			if(low[v]==dfn[v]){//bridge
				//puts("fuck");
				int u=S[top--];cnt++;belong[u]=cnt;size[cnt]=1;
				while(S[top]!=x){
					u=S[top--];
					belong[u]=cnt;
					size[cnt]++;
				}
			}
		}
		else low[x]=min(low[x],dfn[v]);
	}
	//printf("dfn[%d]:%d low:%d\n",x,dfn[x],low[x]);
}
int dp[maxn][2],leave;

void Treedp(int x,int fa){
	//printf("x:%d fa:%d\n",x,fa);
	vis[x]=1;node++;
	int v,son=0;
	dp[x][0]=-INF;dp[x][1]=-INF;
	//int cal=0;
	for(int e=0;e<T[x].size();e++){
		v=T[x][e];
		if(v==fa) continue;son++;
		Treedp(v,x);
		if(dp[v][0]+1>=dp[x][0]){
			dp[x][1]=dp[x][0];
			dp[x][0]=dp[v][0]+1;
		}
		else if(dp[v][0]+1>dp[x][1])
			dp[x][1]=dp[v][0]+1;
	}
	if(dp[x][0]==-INF) //leave
		dp[x][0]=1;
	if(x==fa&&son<=1) leave++;
	if(x!=fa&&son==0) leave++;
	res=max(res,max(dp[x][0],dp[x][0]+dp[x][1]-1));
}

int main(){
	int a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a,&b);if(a==b) continue;
		G[a].push_back(b);G[b].push_back(a);
	}

	for(int i=1;i<=n;i++)
		if(!dfn[i]){
			dfs(i,i);
			if(top>=0){
				cnt++;size[cnt]=0;
				while(top>=0){
				size[cnt]++;belong[S[top--]]=cnt;
				}
			}
		}
	//for(int i=1;i<=n;i++) printf("belong[%d]:%d\n",i,belong[i]);
	for(int i=1;i<=cnt;i++) {f[i][i]=1,ans+=size[i]-1;}
	for(int i=1;i<=n;i++){
		for(int e=0;e<G[i].size();e++){
			if(!f[belong[i]][belong[G[i][e]]]){
				T[belong[i]].push_back(belong[G[i][e]]);T[belong[G[i][e]]].push_back(belong[i]);
				f[belong[i]][belong[G[i][e]]]=f[belong[G[i][e]]][belong[i]]=1;
			}
		}
	}

	int kuai=0;
	for(int i=1;i<=cnt;i++)
		if(!vis[i]){
			res=-INF;leave=0;node=0;
			Treedp(i,i);
			//printf("res:%d leave:%d \n",res,leave);
			ans+=node-res-leave+((res==1)?1:2);
			kuai++;
		}
	ans+=kuai-1;
	printf("%d\n",ans);
	return 0;
}
/*
9 11
1 2
2 3
1 3
3 4
4 5
5 6
5 7
6 7
7 9
7 8
8 9

*/


#include<stdio.h>
#include<string.h>
# include<vector>
#include<algorithm>
using namespace std;
const int maxn=2010;
const int INF=maxn*100;
vector<int> G[maxn],T[maxn];
int n,m;
bool vis[maxn];
bool f[maxn][maxn];
int dfn[maxn],low[maxn],dfs_clock,belong[maxn],cnt=0,size[maxn];
int S[maxn],top=-1;
int ans=0,res,node;

void dfs(int x,int fa){
	dfn[x]=low[x]=++dfs_clock;S[++top]=x;
	//printf("x:%d\n",x);
	int v;
	for(int e=0;e<G[x].size();e++){
		v=G[x][e];
		if(v==fa) continue;
		if(!dfn[v]){
			dfs(v,x);
			low[x]=min(low[x],low[v]);
			if(low[v]==dfn[v]){//bridge
				//puts("fuck");
				int u=S[top--];cnt++;belong[u]=cnt;size[cnt]=1;
				while(S[top]!=x){
					u=S[top--];
					belong[u]=cnt;
					size[cnt]++;
				}
			}
		}
		else low[x]=min(low[x],dfn[v]);
	}
	//printf("dfn[%d]:%d low:%d\n",x,dfn[x],low[x]);
}
int dp[maxn][2],leave;

void Treedp(int x,int fa){
	//printf("x:%d fa:%d\n",x,fa);
	vis[x]=1;node++;
	int v;
	dp[x][0]=-INF;dp[x][1]=-INF;
	//int cal=0;
	for(int e=0;e<T[x].size();e++){
		v=T[x][e];
		if(v==fa) continue;
		Treedp(v,x);
		if(dp[v][0]+1>=dp[x][0]){
			dp[x][1]=dp[x][0];
			dp[x][0]=dp[v][0]+1;
		}
		else if(dp[v][0]+1>dp[x][1])
			dp[x][1]=dp[v][0]+1;
	}
	if(dp[x][0]==-INF) //leave
		dp[x][0]=1,leave++;
	res=max(res,max(dp[x][0]-1,dp[x][0]+dp[x][1]-1-2));
}

int main(){
	int a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a,&b);if(a==b) continue;
		G[a].push_back(b);G[b].push_back(a);
	}

	for(int i=1;i<=n;i++)
		if(!dfn[i]){
			dfs(i,i);
			if(top>=0){
				cnt++;size[cnt]=0;
				while(top>=0){
				size[cnt]++;belong[S[top--]]=cnt;
				}
			}
		}
	//for(int i=1;i<=n;i++) printf("belong[%d]:%d\n",i,belong[i]);
	for(int i=1;i<=cnt;i++) {f[i][i]=1,ans+=size[i]-1;}
	for(int i=1;i<=n;i++){
		for(int e=0;e<G[i].size();e++){
			if(!f[belong[i]][belong[G[i][e]]]){
				T[belong[i]].push_back(belong[G[i][e]]);T[belong[G[i][e]]].push_back(belong[i]);
				f[belong[i]][belong[G[i][e]]]=f[belong[G[i][e]]][belong[i]]=1;
			}
		}
	}

	int kuai=0;
	for(int i=1;i<=cnt;i++)
		if(!vis[i]){
			res=-INF;leave=0;node=0;
			Treedp(i,i);
			//printf("res:%d leave:%d \n",res,leave);
			ans+=node-res-leave;
			kuai++;
		}
	ans+=kuai-1;
	printf("%d\n",ans);
	return 0;
}
/*
9 11
1 2
2 3
1 3
3 4
4 5
5 6
5 7
6 7
7 9
7 8
8 9

*/


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

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define repd(i,r,l) for (int i=(r); i>=(l); i--)
#define rept(i,c) for (typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)

#ifndef ONLINE_JUDGE
#define debug(x) { cerr<<#x<<" = "<<(x)<<endl; }
#else
#define debug(x) {}
#endif

#define maxn 2010
vector<int> e[maxn], g[maxn];
int cn, stp, dfn[maxn], low[maxn], top, stack[maxn], belong[maxn], vis[maxn];

void tarjan(int u, int pre)
{
	top++; stack[top]=u; stp++; dfn[u]=low[u]=stp;
	rept(iter,e[u])
	{
		int v=*iter;
		if (v==pre) continue;
		if (!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else  low[u]=min(low[u],dfn[v]);
	}
	if (dfn[u]==low[u])
	{
		cn++;
		do { belong[stack[top]]=cn; top--; } while (stack[top+1]!=u);
	}
}

int final, best, cnz;
int path[maxn];

void dfs(int cur, int root)
{
	int m1=0, m2=0;
	vis[cur]=1;
	rept(iter,g[cur])
	{
		if (vis[*iter]) continue;
		dfs(*iter,root);
		if (path[*iter]>m1)
			m2=m1, m1=path[*iter];
		else  if (path[*iter]>m2) m2=path[*iter];
	}

	int son=g[cur].size(); if (cur!=root) son--;
	path[cur]=m1+son;
	best=max(best,int(m1+m2+g[cur].size()+1));
}

void solve(int root)
{
	best=0;
	dfs(root,root);
	final+=best;
	cnz++;
}

void lemon()
{
	int n,m; scanf("%d%d",&n,&m);
	rep(i,1,n) e[i].clear();
	rep(i,1,m)
	{
		int x,y; scanf("%d%d",&x,&y);
		e[x].push_back(y); e[y].push_back(x);
	}

	memset(dfn,0,sizeof dfn); stp=0; cn=0; top=0;
	rep(i,1,n) if (dfn[i]==0) tarjan(i,0);

	rep(i,1,cn) g[i].clear();
	rep(i,1,n)
		rept(iter,e[i])
			if (belong[i]!=belong[*iter])
				g[belong[i]].push_back(belong[*iter]);

	rep(i,1,cn)
	{
		sort(g[i].begin(),g[i].end());
		g[i].erase(unique(g[i].begin(),g[i].end()),g[i].end());
	}

	final=0; cnz=0;
	memset(vis,0,sizeof vis);
	rep(i,1,cn) if (!vis[i]) solve(i);

	printf("%d\n",n-final+cnz-1);
}

int main()
{
	ios::sync_with_stdio(true);
	#ifndef ONLINE_JUDGE
		freopen("51F.in","r",stdin);
	#endif
	lemon();
	return 0;
}


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

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define repd(i,r,l) for (int i=(r); i>=(l); i--)
#define rept(i,c) for (typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)

#ifndef ONLINE_JUDGE
#define debug(x) { cerr<<#x<<" = "<<(x)<<endl; }
#else
#define debug(x) {}
#endif

#define maxn 2010
vector<int> e[maxn], g[maxn];
int cn, stp, dfn[maxn], low[maxn], top, stack[maxn], belong[maxn], vis[maxn];

void tarjan(int u, int pre)
{
	top++; stack[top]=u; stp++; dfn[u]=low[u]=stp;
	rept(iter,e[u])
	{
		int v=*iter;
		if (v==pre) continue;
		if (!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else  low[u]=min(low[u],dfn[v]);
	}
	if (dfn[u]==low[u])
	{
		cn++;
		do { belong[stack[top]]=cn; top--; } while (stack[top+1]!=u);
	}
}

int final, best, cnz, cb;
int path[maxn];

void dfs(int cur, int root)
{
	int m1=0, m2=0;
	vis[cur]=1;
	rept(iter,g[cur])
	{
		if (vis[*iter]) continue;
		dfs(*iter,root);
		if (path[*iter]>m1)
			m2=m1, m1=path[*iter];
		else  if (path[*iter]>m2) m2=path[*iter];
	}

	path[cur]=m1+1;
	best=max(best,int(m1+m2+1));
}

int size[maxn];

void go(int cur, int pre)
{
	size[cur]=1;
	rept(iter,g[cur])
		if (*iter!=pre)
		{
			go(*iter,cur); size[cur]+=size[*iter];
		}
	if (g[cur].size()==1 && pre!=-1) vis[cur]=1, cb++;
}

void solve(int root)
{
	cnz++;
	cb=0; go(root,-1);
	if (size[root]<=2) { final+=size[root]; return; }
	if (g[root].size()==1)
	{
		vis[root]=1; cb++;
		root=g[root][0];
	}
	best=0;
	dfs(root,root);
	final+=best+cb;
}

void lemon()
{
	int n,m; scanf("%d%d",&n,&m);
	rep(i,1,n) e[i].clear();
	rep(i,1,m)
	{
		int x,y; scanf("%d%d",&x,&y);
		e[x].push_back(y); e[y].push_back(x);
	}

	memset(dfn,0,sizeof dfn); stp=0; cn=0; top=0;
	rep(i,1,n) if (dfn[i]==0) tarjan(i,0);

	rep(i,1,cn) g[i].clear();
	rep(i,1,n)
		rept(iter,e[i])
			if (belong[i]!=belong[*iter])
				g[belong[i]].push_back(belong[*iter]);

	rep(i,1,cn)
	{
		sort(g[i].begin(),g[i].end());
		g[i].erase(unique(g[i].begin(),g[i].end()),g[i].end());
	}

	final=0; cnz=0;
	memset(vis,0,sizeof vis);
	rep(i,1,cn) if (!vis[i]) solve(i);

	printf("%d\n",n-final+cnz-1);
}

int main()
{
	ios::sync_with_stdio(true);
	#ifndef ONLINE_JUDGE
		freopen("51F.in","r",stdin);
	#endif
	lemon();
	return 0;
}


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

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define repd(i,r,l) for (int i=(r); i>=(l); i--)
#define rept(i,c) for (typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)

#ifndef ONLINE_JUDGE
#define debug(x) { cerr<<#x<<" = "<<(x)<<endl; }
#else
#define debug(x) {}
#endif

#define maxn 2010
vector<int> e[maxn], g[maxn];
int cn, stp, dfn[maxn], low[maxn], top, stack[maxn], belong[maxn], vis[maxn];

void tarjan(int u, int pre)
{
	top++; stack[top]=u; stp++; dfn[u]=low[u]=stp;
	rept(iter,e[u])
	{
		int v=*iter;
		if (v==pre) continue;
		if (!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else  low[u]=min(low[u],dfn[v]);
	}
	if (dfn[u]==low[u])
	{
		cn++;
		do { belong[stack[top]]=cn; top--; } while (stack[top+1]!=u);
	}
}

int final, best;
int path[maxn];

void dfs(int cur, int root)
{
	int m1=0, m2=0;
	vis[cur]=1;
	rept(iter,g[cur])
	{
		if (vis[*iter]) continue;
		dfs(*iter,root);
		if (path[*iter]>m1)
			m2=m1, m1=path[*iter];
		else  if (path[*iter]>m2) m2=path[*iter];
	}

	int son=g[cur].size(); if (cur!=root) son--;
	path[cur]=m1+son;
	best=max(best,int(m1+m2+g[cur].size()+1));
}

void solve(int root)
{
	best=0;
	dfs(root,root);
	final+=best;
}

void lemon()
{
	int n,m; scanf("%d%d",&n,&m);
	rep(i,1,n) e[i].clear();
	rep(i,1,m)
	{
		int x,y; scanf("%d%d",&x,&y);
		e[x].push_back(y); e[y].push_back(x);
	}

	memset(dfn,0,sizeof dfn); stp=0; cn=0; top=0;
	rep(i,1,n) if (dfn[i]==0) tarjan(i,0);

	rep(i,1,cn) g[i].clear();
	rep(i,1,n)
		rept(iter,e[i])
			if (belong[i]!=belong[*iter])
				g[belong[i]].push_back(belong[*iter]);

	rep(i,1,cn)
	{
		sort(g[i].begin(),g[i].end());
		g[i].erase(unique(g[i].begin(),g[i].end()),g[i].end());
	}

	final=0;
	memset(vis,0,sizeof vis);
	rep(i,1,cn)
		if (!vis[i])
			solve(i);

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

int main()
{
	ios::sync_with_stdio(true);
	#ifndef ONLINE_JUDGE
		freopen("51F.in","r",stdin);
	#endif
	lemon();
	return 0;
}


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

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define repd(i,r,l) for (int i=(r); i>=(l); i--)
#define rept(i,c) for (typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)

#ifndef ONLINE_JUDGE
#define debug(x) { cerr<<#x<<" = "<<(x)<<endl; }
#else
#define debug(x) {}
#endif

#define maxn 2010
vector<int> e[maxn], g[maxn];
int cn, stp, dfn[maxn], low[maxn], top, stack[maxn], belong[maxn], vis[maxn];

void tarjan(int u, int pre)
{
	top++; stack[top]=u; stp++; dfn[u]=low[u]=stp;
	rept(iter,e[u])
	{
		int v=*iter;
		if (v==pre) continue;
		if (!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else  low[u]=min(low[u],dfn[v]);
	}
	if (dfn[u]==low[u])
	{
		cn++;
		do { belong[stack[top]]=cn; top--; } while (stack[top+1]!=u);
	}
}

int final, best, cnz, cb;
int path[maxn];

void dfs(int cur, int root)
{
	int m1=0, m2=0;
	vis[cur]=1;
	rept(iter,g[cur])
	{
		if (vis[*iter]) continue;
		dfs(*iter,root);
		if (path[*iter]>m1)
			m2=m1, m1=path[*iter];
		else  if (path[*iter]>m2) m2=path[*iter];
	}

	path[cur]=m1+1;
	best=max(best,int(m1+m2+1));
}

int size[maxn];

void go(int cur, int pre)
{
	size[cur]=1;
	rept(iter,g[cur])
		if (*iter!=pre)
		{
			go(*iter,cur); size[cur]+=size[*iter];
		}
	if (g[cur].size()==1 && pre!=-1) vis[cur]=1, cb++;
}

void solve(int root)
{
	cb=0; go(root,-1);
	if (g[root].size()==1)
	{
		vis[root]=1; cb++;
		root=g[root][0];
	}
	best=0;
	dfs(root,root);
	final+=best+cb;
	cnz++;
}

void lemon()
{
	int n,m; scanf("%d%d",&n,&m);
	rep(i,1,n) e[i].clear();
	rep(i,1,m)
	{
		int x,y; scanf("%d%d",&x,&y);
		e[x].push_back(y); e[y].push_back(x);
	}

	memset(dfn,0,sizeof dfn); stp=0; cn=0; top=0;
	rep(i,1,n) if (dfn[i]==0) tarjan(i,0);

	rep(i,1,cn) g[i].clear();
	rep(i,1,n)
		rept(iter,e[i])
			if (belong[i]!=belong[*iter])
				g[belong[i]].push_back(belong[*iter]);

	rep(i,1,cn)
	{
		sort(g[i].begin(),g[i].end());
		g[i].erase(unique(g[i].begin(),g[i].end()),g[i].end());
	}

	final=0; cnz=0;
	memset(vis,0,sizeof vis);
	rep(i,1,cn) if (!vis[i]) solve(i);

	printf("%d\n",n-final+cnz-1);
}

int main()
{
	ios::sync_with_stdio(true);
	#ifndef ONLINE_JUDGE
		freopen("51F.in","r",stdin);
	#endif
	lemon();
	return 0;
}


#include <bits/stdc++.h>
#define Rep(i,n) for(int i = 1;i <= n;++ i)
#define rep(i,a,b) for(int i = a;i <= b;++ i)
#define Dwn(i,n) for(int i = n;i ;i --)
#define dwn(i,a,b) for(int i = a;i >= b;-- i)
#define v edge[i].to
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
using namespace std;
const int M = 100005;
const int N = 2005;
int scc,bel[N],stk[N],q[N],low[N],tp,tim,sz[N],dfn[N],n,m,vis[N],cur,cx;
namespace Gr
{
	struct Edge{int next,to;}edge[M*2];
	int head[N],cnt;
	void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
	void solve(int x,int ff,int ds)
	{
		vis[x] = 1;
		if(ds > cur)cur = ds,cx = x;
		RepG(i,x)if(v != ff)solve(v,x,ds + 1);
	}
};
struct Edge{int next,to;}edge[M*2];
int head[N],cnt,du[N];
void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
void dfs(int x,int fa = 0)
{
	low[x] = dfn[stk[++ tp] = x] = ++ tim;
	RepG(i,x)
	{
		if((i ^ 1) == fa)continue;
		if(!dfn[v])dfs(v,i),low[x] = min(low[x],low[v]);
		else if(!bel[v])low[x] = min(low[x],dfn[v]);
	}
	if(low[x] == dfn[x])
	{
		int y;++ scc;
		do{y = stk[tp --];bel[y] = scc;++ sz[scc];}while(y != x);
	}
}
int ex[M],ey[M];
int main()
{
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	memset(Gr :: head,-1,sizeof(Gr :: head));
	Gr :: cnt = 0;
	Rep(i,m)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		ex[i] = a,ey[i] = b;
		save(a,b),save(b,a);
	}
	Rep(i,n)if(!dfn[i])dfs(i);
	int ans = 0;
	Rep(i,m)
	{
		int x = ex[i],y = ey[i];
		if(bel[x] != bel[y])
		{
			Gr :: save(bel[x],bel[y]);
			Gr :: save(bel[y],bel[x]);
			++ du[bel[x]],++ du[bel[y]];
		}
	}
	int re = 0;
	Rep(i,scc)if(du[i] <= 1)re ++;
	Rep(i,scc)if(!vis[i])
	{
		cur = 0;Gr :: solve(i,0,1);
		cur = 0;Gr :: solve(cx,0,1);
		if(cur == 1)re --;
		else re += cur - 3;
	}
	ans = n;
	ans -= re;ans --;
	printf("%d\n",ans);
	return 0;
}


#include <bits/stdc++.h>
#define Rep(i,n) for(int i = 1;i <= n;++ i)
#define rep(i,a,b) for(int i = a;i <= b;++ i)
#define Dwn(i,n) for(int i = n;i ;i --)
#define dwn(i,a,b) for(int i = a;i >= b;-- i)
#define v edge[i].to
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
using namespace std;
const int M = 100005;
const int N = 2005;
int scc,bel[N],stk[N],q[N],low[N],tp,tim,sz[N],dfn[N],n,m,vis[N],cur,cx;
namespace Gr
{
	struct Edge{int next,to;}edge[M];
	int head[N],cnt;
	void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
	void solve(int x,int ff,int ds)
	{
		vis[x] = 1;
		if(ds > cur)cur = ds,cx = x;
		RepG(i,x)if(v != ff)solve(v,x,ds + 1);
	}
};
struct Edge{int next,to;}edge[M];
int head[N],cnt,du[N];
void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
void dfs(int x,int fa = 0)
{
	low[x] = dfn[stk[++ tp] = x] = ++ tim;
	RepG(i,x)
	{
		if((i ^ 1) == fa)continue;
		if(!dfn[v])dfs(v,i),low[x] = min(low[x],low[v]);
		else if(!bel[v])low[x] = min(low[x],dfn[v]);
	}
	if(low[x] == dfn[x])
	{
		int y;++ scc;
		do{y = stk[tp --];bel[y] = scc;++ sz[scc];}while(y != x);
	}
}
int ex[M],ey[M];
int main()
{
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	memset(Gr :: head,-1,sizeof(Gr :: head));
	Gr :: cnt = 0;
	Rep(i,m)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		ex[i] = a,ey[i] = b;
		save(a,b),save(b,a);
	}
	Rep(i,n)if(!dfn[i])dfs(i);
	int ans = 0;
	Rep(i,m)
	{
		int x = ex[i],y = ey[i];
		if(bel[x] != bel[y])
		{
			Gr :: save(bel[x],bel[y]);
			Gr :: save(bel[y],bel[x]);
			++ du[bel[x]],++ du[bel[y]];
		}
	}
	int re = 0;
	Rep(i,scc)if(du[i] <= 1)re ++;
	Rep(i,scc)if(!vis[i])
	{
		cur = 0;Gr :: solve(i,0,1);
		cur = 0;Gr :: solve(cx,0,1);
		if(cur == 1)re --;
		else re += cur - 3;
	}
	ans = n;
	ans -= re;ans --;
	printf("%d\n",ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

const int MAXN = 2010;
const int MAXM = 101010;

struct Edge
{
	int to, next;
};

int dfn[MAXN], low[MAXN], stack[MAXN], cnt, id[MAXN], index, tot;
int p[MAXN], z = -1;
int v[MAXN][MAXN], num[MAXN];
int l, leaf;
int n, m, ans, tim;
bool visit[MAXN];
Edge e[MAXM];

void add(int u, int v)
{
	e[++ z].to = v;
	e[z].next = p[u];
	p[u] = z;
}

void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++ index;
	stack[++ tot] = u;
	for(int temp = p[u]; temp != -1; temp = e[temp].next)
		if(!dfn[e[temp].to])
		{
			tarjan(e[temp].to, u);
			low[u] = min(low[u], low[e[temp].to]);
		}
		else if(e[temp].to != fa)
			low[u] = min(low[u], dfn[e[temp].to]);
	if(dfn[u] == low[u])
	{
		++ cnt;
		int v;
		do
		{
			v = stack[tot --];
			id[v] = cnt;
		}
		while(u != v);
	}
}

int dfs(int u, int fa)
{
	visit[u] = 1;
	int MAX_F = 0, MAX_S = 0;
	leaf += num[u] < 2;
	for(int i = 1; i <= num[u]; i ++)
		if(v[u][i] != fa)
		{
			int t = dfs(v[u][i], u);
			if(t > MAX_F)
			{
				MAX_S = MAX_F;
				MAX_F = t;
			}
			else if(t > MAX_S)
				MAX_S = t;
		}
	l = max(l, MAX_F + MAX_S + 1);
	return MAX_F + 1;
}

void init()
{
	memset(p, -1, sizeof(p));
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++)
	{
		 int u, v;
		 scanf("%d%d", &u, &v);
		 add(u, v);
		 add(v, u);
	}
}

void process()
{
	for(int i = 1; i <= n; i ++)
		if(!dfn[i])
			tarjan(i, 0);
//	for(int i = 1; i <= n; i ++)
//		printf("%d %d %d\n", dfn[i], low[i], id[i]);
	for(int i = 1; i <= n; i ++)
		for(int temp = p[i]; temp != -1; temp = e[temp].next)
			if(id[i] != id[e[temp].to])
				v[id[i]][++ num[id[i]]] = id[e[temp].to];
	/*
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= num[i]; j ++)
			printf("%d ", v[i][j]);
		printf("\n");
	}
	*/
	for(int i = 1; i <= cnt; i ++)
		if(!visit[i])
		{
			tim ++;
			l = leaf = 0;
			dfs(i, 0);
			if(l == 1 && leaf == 1)
				ans ++;
			else
				ans += l + leaf - 2;
		}
}

int main()
{
	init();
	process();
	printf("%d\n", n - ans + tim - 1);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

const int MAXN = 2010;
const int MAXM = 201010;

struct Edge
{
	int to, next;
};

int dfn[MAXN], low[MAXN], stack[MAXN], cnt, id[MAXN], index, tot;
int p[MAXN], z = -1;
int v[MAXN][MAXN], num[MAXN];
int l, leaf;
int n, m, ans, tim;
bool visit[MAXN];
Edge e[MAXM];

void add(int u, int v)
{
	e[++ z].to = v;
	e[z].next = p[u];
	p[u] = z;
}

void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++ index;
	stack[++ tot] = u;
	for(int temp = p[u]; temp != -1; temp = e[temp].next)
		if(!dfn[e[temp].to])
		{
			tarjan(e[temp].to, u);
			low[u] = min(low[u], low[e[temp].to]);
		}
		else if(e[temp].to != fa)
			low[u] = min(low[u], dfn[e[temp].to]);
	if(dfn[u] == low[u])
	{
		++ cnt;
		int v;
		do
		{
			v = stack[tot --];
			id[v] = cnt;
		}
		while(u != v);
	}
}

int dfs(int u, int fa)
{
	visit[u] = 1;
	int MAX_F = 0, MAX_S = 0;
	leaf += num[u] < 2;
	for(int i = 1; i <= num[u]; i ++)
		if(v[u][i] != fa)
		{
			int t = dfs(v[u][i], u);
			if(t > MAX_F)
			{
				MAX_S = MAX_F;
				MAX_F = t;
			}
			else if(t > MAX_S)
				MAX_S = t;
		}
	l = max(l, MAX_F + MAX_S + 1);
	return MAX_F + 1;
}

void init()
{
	memset(p, -1, sizeof(p));
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++)
	{
		 int u, v;
		 scanf("%d%d", &u, &v);
		 add(u, v);
		 add(v, u);
	}
}

void process()
{
	for(int i = 1; i <= n; i ++)
		if(!dfn[i])
			tarjan(i, 0);
//	for(int i = 1; i <= n; i ++)
//		printf("%d %d %d\n", dfn[i], low[i], id[i]);
	for(int i = 1; i <= n; i ++)
		for(int temp = p[i]; temp != -1; temp = e[temp].next)
			if(id[i] != id[e[temp].to])
				v[id[i]][++ num[id[i]]] = id[e[temp].to];
	/*
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= num[i]; j ++)
			printf("%d ", v[i][j]);
		printf("\n");
	}
	*/
	for(int i = 1; i <= cnt; i ++)
		if(!visit[i])
		{
			tim ++;
			l = leaf = 0;
			dfs(i, 0);
			if(l == 1 && leaf == 1)
				ans ++;
			else
				ans += l + leaf - 2;
		}
}

int main()
{
	init();
	process();
	printf("%d\n", n - ans + tim - 1);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

const int MAXN = 2010;
const int MAXM = 201010;

struct Edge
{
	int to, next;
};

int dfn[MAXN], low[MAXN], stack[MAXN], cnt, id[MAXN], index, tot;
int p[MAXN], z = -1;
int v[MAXN][MAXN], num[MAXN];
int l, leaf;
int n, m, ans, tim;
bool visit[MAXN];
Edge e[MAXM];

void add(int u, int v)
{
	e[++ z].to = v;
	e[z].next = p[u];
	p[u] = z;
}

void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++ index;
	stack[++ tot] = u;
	for(int temp = p[u]; temp != -1; temp = e[temp].next)
		if(!dfn[e[temp].to])
		{
			tarjan(e[temp].to, u);
			low[u] = min(low[u], low[e[temp].to]);
		}
		else if(e[temp].to != fa)
			low[u] = min(low[u], dfn[e[temp].to]);
	if(dfn[u] == low[u])
	{
		++ cnt;
		int v;
		do
		{
			v = stack[tot --];
			id[v] = cnt;
		}
		while(u != v);
	}
}

int dfs(int u, int fa)
{
	visit[u] = 1;
	int MAX_F = 0, MAX_S = 0;
	leaf += num[u] < 2;
	for(int i = 1; i <= num[u]; i ++)
		if(v[u][i] != fa)
		{
			int t = dfs(v[u][i], u);
			if(t > MAX_F)
			{
				MAX_S = MAX_F;
				MAX_F = t;
			}
			else if(t > MAX_S)
				MAX_S = t;
		}
	l = max(l, MAX_F + MAX_S + 1);
	return MAX_F + 1;
}

void init()
{
	memset(p, -1, sizeof(p));
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++)
	{
		 int u, v;
		 scanf("%d%d", &u, &v);
		 add(u, v);
		 add(v, u);
	}
}

void process()
{
	for(int i = 1; i <= n; i ++)
		if(!dfn[i])
			tarjan(i, 0);
	for(int i = 1; i <= n; i ++)
		for(int temp = p[i]; temp != -1; temp = e[temp].next)
			if(id[i] != id[e[temp].to])
				v[id[i]][++ num[id[i]]] = id[e[temp].to];
	for(int i = 1; i <= cnt; i ++)
		if(!visit[i])
		{
			tim ++;
			l = leaf = 0;
			dfs(i, 0);
			if(l == 1 && leaf == 1)
				ans ++;
			else
				ans += l + leaf - 2;
		}
}

int main()
{
	init();
	process();
	printf("%d\n", n - ans + tim - 1);
	return 0;
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
//#include <cmath>
#define ran2 (rand() % 32000 * 32000 + rand() % 32000)
using namespace std;

int m,n,j,k,l,i,o,p,__t,ans,maxi,tot,tot_point;

char ch;
void read(int &a){
	for (ch = getchar();(ch < '0' || ch > '9') && (ch != '-');ch = getchar());
	if (ch == '-') a = 0,__t = -1; else a = ch - '0',__t = 1;
	for (ch = getchar();ch >= '0' && ch <= '9';ch = getchar()) a = a * 10 + ch - '0';
	a *= __t;
}
#define mx 200000
bool V[2010][2010],notsolve[2010];
struct graph{
	int Be[mx],E[mx],N[mx],T,sigma[mx];

	void make(int i,int j,int k){
		N[++ T] = Be[i]; Be[i] = T; E[T] = j;
		sigma[i] ++;
		//printf("%d %d\n",i,j);
		if (k) make(j,i,0);
	}

	graph(){
		T = 1;
	}

	int DFS(int P,int fa){
		tot_point ++;
		notsolve[P] = 1;
		int a = 0,b = 0,c;
		if (sigma[P] < 2) tot ++;
		for (int i = Be[P];i;i = N[i]) if (E[i] != fa){
			int def = E[i];
			c = DFS(E[i],P);
			if (c > a) b = a,a = c; else
			if (c > b) b = c;
		}
		maxi = max(maxi,a + b + 1);
		return a + 1;
	}

};

struct main_graph{
	graph a1,a2;

	int low[mx],dfn[mx],stack[mx],top,instack[mx],height,C[mx],color;

	void tarjon(int P,int forbiden){
		low[P] = dfn[P] = ++ height;
		instack[stack[++ top] = P] = 1;
		for (int i = a1.Be[P];i;i = a1.N[i])
			if ((i ^ 1) != forbiden){
				if (low[a1.E[i]] == 0)
					tarjon(a1.E[i],i),low[P] = min(low[P],low[a1.E[i]]); else
				if (instack[a1.E[i]])
					low[P] = min(low[P],dfn[a1.E[i]]);
			}
		if (low[P] == dfn[P])
			for (ans --,color ++;stack[top + 1] != P;top --)
				C[stack[top]] = color,instack[stack[top]] = 0,ans ++;
	}

	void solve(){
		for (int i = 1;i <= m;i ++)
			if (low[i] == 0)
				tarjon(i,0);
		for (int i = 1;i <= n;i ++){
			int f1 = C[a1.E[i * 2]],f2 = C[a1.E[i * 2 + 1]];
			if (f1 != f2 && V[f1][f2] == 0){
				V[f1][f2] = 1;
				V[f2][f1] = 1;
				a2.make(f1,f2,1);
			}
		}
		ans --;
		for (int i = 1;i <= color;i ++)
			if (notsolve[i] == 0){
				tot_point = tot = maxi = 0;
				ans ++;
				a2.DFS(i,0);
				ans += tot_point - maxi - tot + 2;
			}
		cout << ans << endl;
	}

} pic;

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

	read(m),read(n);
	for (int i = 1;i <= n;i ++){
		read(j),read(k);
		pic.a1.make(j,k,1);
	}
	pic.solve();
	//fclose(stdin); fclose(stdout);
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
//#include <cmath>
#define ran2 (rand() % 32000 * 32000 + rand() % 32000)
using namespace std;

int m,n,j,k,l,i,o,p,__t,ans,maxi,tot,tot_point;

char ch;
void read(int &a){
	for (ch = getchar();(ch < '0' || ch > '9') && (ch != '-');ch = getchar());
	if (ch == '-') a = 0,__t = -1; else a = ch - '0',__t = 1;
	for (ch = getchar();ch >= '0' && ch <= '9';ch = getchar()) a = a * 10 + ch - '0';
	a *= __t;
}
#define mx 200000
bool V[2010][2010],notsolve[2010];
struct graph{
	int Be[mx],E[mx],N[mx],T,sigma[mx];

	void make(int i,int j,int k){
		N[++ T] = Be[i]; Be[i] = T; E[T] = j;
		sigma[i] ++;
		//printf("%d %d\n",i,j);
		if (k) make(j,i,0);
	}

	graph(){
		T = 1;
	}

	int DFS(int P,int fa){
		tot_point ++;
		notsolve[P] = 1;
		int a = 0,b = 0,c;
		if (sigma[P] < 2) tot ++;
		for (int i = Be[P];i;i = N[i]) if (E[i] != fa){
			int def = E[i];
			c = DFS(E[i],P);
			if (c > a) b = a,a = c; else
			if (c > b) b = c;
		}
		maxi = max(maxi,a + b + 1);
		return a + 1;
	}

};

struct main_graph{
	graph a1,a2;

	int low[mx],dfn[mx],stack[mx],top,instack[mx],height,C[mx],color;

	void tarjon(int P,int forbiden){
		low[P] = dfn[P] = ++ height;
		instack[stack[++ top] = P] = 1;
		for (int i = a1.Be[P];i;i = a1.N[i])
			if ((i ^ 1) != forbiden){
				if (low[a1.E[i]] == 0)
					tarjon(a1.E[i],i),low[P] = min(low[P],low[a1.E[i]]); else
				if (instack[a1.E[i]])
					low[P] = min(low[P],dfn[a1.E[i]]);
			}
		if (low[P] == dfn[P])
			for (ans --,color ++;stack[top + 1] != P;top --)
				C[stack[top]] = color,instack[stack[top]] = 0,ans ++;
	}

	void solve(){
		for (int i = 1;i <= m;i ++)
			if (low[i] == 0)
				tarjon(i,0);
		for (int i = 1;i <= n;i ++){
			int f1 = C[a1.E[i * 2]],f2 = C[a1.E[i * 2 + 1]];
			if (f1 != f2 && V[f1][f2] == 0){
				V[f1][f2] = 1;
				V[f2][f1] = 1;
				a2.make(f1,f2,1);
			}
		}
		ans --;
		for (int i = 1;i <= color;i ++)
			if (notsolve[i] == 0){
				tot = maxi = 0;
				ans ++;
				a2.DFS(i,0);
				if (tot == maxi && maxi == 1) ans += 1; else
				ans += tot_point - maxi - tot + 2;
			}
		cout << ans << endl;
	}

} pic;

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

	read(m),read(n);
	for (int i = 1;i <= n;i ++){
		read(j),read(k);
		pic.a1.make(j,k,1);
	}
	pic.solve();
	//fclose(stdin); fclose(stdout);
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
//#include <cmath>
#define ran2 (rand() % 32000 * 32000 + rand() % 32000)
using namespace std;

int m,n,j,k,l,i,o,p,__t,ans,maxi,tot,tot_point;

char ch;
void read(int &a){
	for (ch = getchar();(ch < '0' || ch > '9') && (ch != '-');ch = getchar());
	if (ch == '-') a = 0,__t = -1; else a = ch - '0',__t = 1;
	for (ch = getchar();ch >= '0' && ch <= '9';ch = getchar()) a = a * 10 + ch - '0';
	a *= __t;
}
#define mx 200000
bool V[2010][2010],notsolve[2010];
struct graph{
	int Be[mx],E[mx],N[mx],T,sigma[mx];

	void make(int i,int j,int k){
		N[++ T] = Be[i]; Be[i] = T; E[T] = j;
		sigma[i] ++;
		//printf("%d %d\n",i,j);
		if (k) make(j,i,0);
	}

	graph(){
		T = 1;
	}

	int DFS(int P,int fa){
		tot_point ++;
		notsolve[P] = 1;
		int a = 0,b = 0,c;
		if (sigma[P] < 2) tot ++;
		for (int i = Be[P];i;i = N[i]) if (E[i] != fa){
			int def = E[i];
			c = DFS(E[i],P);
			if (c > a) b = a,a = c; else
			if (c > b) b = c;
		}
		maxi = max(maxi,a + b + 1);
		return a + 1;
	}

};

struct main_graph{
	graph a1,a2;

	int low[mx],dfn[mx],stack[mx],top,instack[mx],height,C[mx],color;

	void tarjon(int P,int forbiden){
		low[P] = dfn[P] = ++ height;
		instack[stack[++ top] = P] = 1;
		for (int i = a1.Be[P];i;i = a1.N[i])
			if ((i ^ 1) != forbiden){
				if (low[a1.E[i]] == 0)
					tarjon(a1.E[i],i),low[P] = min(low[P],low[a1.E[i]]); else
				if (instack[a1.E[i]])
					low[P] = min(low[P],dfn[a1.E[i]]);
			}
		if (low[P] == dfn[P])
			for (ans --,color ++;stack[top + 1] != P;top --)
				C[stack[top]] = color,instack[stack[top]] = 0,ans ++;
	}

	void solve(){
		for (int i = 1;i <= m;i ++)
			if (low[i] == 0)
				tarjon(i,0);
		for (int i = 1;i <= n;i ++){
			int f1 = C[a1.E[i * 2]],f2 = C[a1.E[i * 2 + 1]];
			if (f1 != f2 && V[f1][f2] == 0){
				V[f1][f2] = 1;
				V[f2][f1] = 1;
				a2.make(f1,f2,1);
			}
		}
		ans --;
		for (int i = 1;i <= color;i ++)
			if (notsolve[i] == 0){
				tot_point = tot = maxi = 0;
				ans ++;
				a2.DFS(i,0);
				if (tot_point == 1) continue;
				ans += tot_point - maxi - tot + 2;
			}
		cout << ans << endl;
	}

} pic;

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

	read(m),read(n);
	for (int i = 1;i <= n;i ++){
		read(j),read(k);
		pic.a1.make(j,k,1);
	}
	pic.solve();
	//fclose(stdin); fclose(stdout);
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
//#include <cmath>
#define ran2 (rand() % 32000 * 32000 + rand() % 32000)
using namespace std;

int m,n,j,k,l,i,o,p,__t,ans,maxi,tot;

char ch;
void read(int &a){
	for (ch = getchar();(ch < '0' || ch > '9') && (ch != '-');ch = getchar());
	if (ch == '-') a = 0,__t = -1; else a = ch - '0',__t = 1;
	for (ch = getchar();ch >= '0' && ch <= '9';ch = getchar()) a = a * 10 + ch - '0';
	a *= __t;
}
#define mx 200000
bool V[2010][2010],notsolve[2010];
struct graph{
	int Be[mx],E[mx],N[mx],T,sigma[mx];

	void make(int i,int j,int k){
		N[++ T] = Be[i]; Be[i] = T; E[T] = j;
		sigma[i] ++;
		printf("%d %d\n",i,j);
		if (k) make(j,i,0);
	}

	graph(){
		T = 1;
	}

	int DFS(int P,int fa){
		tot ++;
		notsolve[P] = 1;
		int a = 0,b = 0,c;
		for (int i = Be[P];i;i = N[i]) if (E[i] != fa){
			int def = E[i];
			c = DFS(E[i],P);
			if (c > a) b = a,a = c; else
			if (c > b) b = c;
		}
		maxi = max(maxi,a + b + sigma[P] + 1 - (a > 0) - (b > 0));
		return 1 + a + ((sigma[P] - 2 < 0) ? (0) : (sigma[P] - 2));
	}

};

struct main_graph{
	graph a1,a2;

	int low[mx],dfn[mx],stack[mx],top,instack[mx],height,C[mx],color;

	void tarjon(int P,int forbiden){
		low[P] = dfn[P] = ++ height;
		instack[stack[++ top] = P] = 1;
		for (int i = a1.Be[P];i;i = a1.N[i])
			if ((i ^ 1) != forbiden){
				if (low[a1.E[i]] == 0)
					tarjon(a1.E[i],i),low[P] = min(low[P],low[a1.E[i]]); else
				if (instack[a1.E[i]])
					low[P] = min(low[P],dfn[a1.E[i]]);
			}
		if (low[P] == dfn[P])
			for (ans --,color ++;stack[top + 1] != P;top --)
				C[stack[top]] = color,instack[stack[top]] = 0,ans ++;
	}

	void solve(){
		for (int i = 1;i <= m;i ++)
			if (low[i] == 0)
				tarjon(i,0);
		for (int i = 1;i <= n;i ++){
			int f1 = C[a1.E[i * 2]],f2 = C[a1.E[i * 2 + 1]];
			if (f1 != f2 && V[f1][f2] == 0){
				V[f1][f2] = 1;
				V[f2][f1] = 1;
				a2.make(f1,f2,1);
			}
		}
		ans --;
		for (int i = 1;i <= color;i ++)
			if (notsolve[i] == 0){
				tot = maxi = 0;
				a2.DFS(i,0);
				ans += tot - maxi + 1;
			}
		cout << ans << endl;
	}

} pic;

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

	read(m),read(n);
	for (int i = 1;i <= n;i ++){
		read(j),read(k);
		pic.a1.make(j,k,1);
	}
	pic.solve();
	//fclose(stdin); fclose(stdout);
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
//#include <cmath>
#define ran2 (rand() % 32000 * 32000 + rand() % 32000)
using namespace std;

int m,n,j,k,l,i,o,p,__t,ans,maxi,tot;

char ch;
void read(int &a){
	for (ch = getchar();(ch < '0' || ch > '9') && (ch != '-');ch = getchar());
	if (ch == '-') a = 0,__t = -1; else a = ch - '0',__t = 1;
	for (ch = getchar();ch >= '0' && ch <= '9';ch = getchar()) a = a * 10 + ch - '0';
	a *= __t;
}
#define mx 200000
bool V[2010][2010],notsolve[2010];
struct graph{
	int Be[mx],E[mx],N[mx],T,sigma[mx];

	void make(int i,int j,int k){
		N[++ T] = Be[i]; Be[i] = T; E[T] = j;
		sigma[i] ++;
		//printf("%d %d\n",i,j);
		if (k) make(j,i,0);
	}

	graph(){
		T = 1;
	}

	int DFS(int P,int fa){
		tot ++;
		notsolve[P] = 1;
		int a = 0,b = 0,c;
		for (int i = Be[P];i;i = N[i]) if (E[i] != fa){
			int def = E[i];
			c = DFS(E[i],P);
			if (c > a) b = a,a = c; else
			if (c > b) b = c;
		}
		maxi = max(maxi,a + b + sigma[P] + 1 - (a > 0) - (b > 0));
		return 1 + a + ((sigma[P] - 2 < 0) ? (0) : (sigma[P] - 2));
	}

};

struct main_graph{
	graph a1,a2;

	int low[mx],dfn[mx],stack[mx],top,instack[mx],height,C[mx],color;

	void tarjon(int P,int forbiden){
		low[P] = dfn[P] = ++ height;
		instack[stack[++ top] = P] = 1;
		for (int i = a1.Be[P];i;i = a1.N[i])
			if ((i ^ 1) != forbiden){
				if (low[a1.E[i]] == 0)
					tarjon(a1.E[i],i),low[P] = min(low[P],low[a1.E[i]]); else
				if (instack[a1.E[i]])
					low[P] = min(low[P],dfn[a1.E[i]]);
			}
		if (low[P] == dfn[P])
			for (ans --,color ++;stack[top + 1] != P;top --)
				C[stack[top]] = color,instack[stack[top]] = 0,ans ++;
	}

	void solve(){
		for (int i = 1;i <= m;i ++)
			if (low[i] == 0)
				tarjon(i,0);
		for (int i = 1;i <= n;i ++){
			int f1 = C[a1.E[i * 2]],f2 = C[a1.E[i * 2 + 1]];
			if (f1 != f2 && V[f1][f2] == 0){
				V[f1][f2] = 1;
				V[f2][f1] = 1;
				a2.make(f1,f2,1);
			}
		}
		ans --;
		for (int i = 1;i <= color;i ++)
			if (notsolve[i] == 0){
				tot = maxi = 0;
				a2.DFS(i,0);
				ans += tot - maxi + 1;
			}
		cout << ans << endl;
	}

} pic;

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

	read(m),read(n);
	for (int i = 1;i <= n;i ++){
		read(j),read(k);
		pic.a1.make(j,k,1);
	}
	pic.solve();
	//fclose(stdin); fclose(stdout);
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

int N,M;
int hash[100010]={0};
struct bian_
{
	int to;
	int next;
}bian[200010]={{0,0}};
int First[2010]={0};
int dfn[2010]={0};
int dfsp=0;
int Low[2010]={0};
int flag[2010]={0};
int belong[2010]={0};
int bep=0;
int bianp=0;
int Mdist=0,pot=0;
int du[2010]={0};
int Ans=0;

void Add(int p,int q,int k)
{
	bian[k].to=q;
	bian[k].next=First[p];
	First[p]=k;
	return;
}

void dfs(int cnt)
{
	dfn[cnt]=++dfsp;
	Low[cnt]=dfn[cnt];
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		int u=bian[i].to;
		if(hash[(i+1)>>1]==1) continue;
		hash[(i+1)>>1]=1;
		if(dfn[u]==0)
		{
			dfs(u);
			Low[cnt]=min(Low[cnt],Low[u]);
			if(Low[u]==dfn[u])
				flag[(i+1)>>1]=1;
		}
		else Low[cnt]=min(Low[cnt],dfn[u]);
	}
	return;
}

void dfs2(int cnt)
{
	belong[cnt]=bep;
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		if(flag[(i+1)>>1]==1) continue;
		int u=bian[i].to;
		if(belong[u]!=0) continue;
		dfs2(u);
	}
	return;
}

void dfs3(int cnt,int fa,int dd)
{
	hash[cnt]=1;
	if(pot==0 || dd>Mdist)
		pot=cnt,Mdist=dd;
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		int u=bian[i].to;
		if(u==fa) continue;
		dfs3(u,cnt,dd+1);
	}
	return;
}

void done(int X)
{
	Mdist=0,pot=0;
	dfs3(X,0,0);
	int O=pot;
	Mdist=pot=0;
	dfs3(O,0,0);
	if(Mdist>0) Ans-=Mdist-2;
	return;
}

int main()
{
	cin>>N>>M;
	for(int i=1;i<=M;i++)
	{
		int p,q;
		scanf("%d%d",&p,&q);
		if(p==q)
		{
			i--,M--;
			continue;
		}
		Add(p,q,(i<<1)-1);
		Add(q,p,i<<1);
	}
	for(int i=1;i<=N;i++)
	{
		if(dfn[i]==0)
			dfs(i);
	}
	for(int i=1;i<=N;i++)
	{
		if(belong[i]==0)
		{
			bep++;
			dfs2(i);
		}
	}
	memset(First,0,sizeof(First));
	for(int i=1;i<=M;i++)
	{
		if(flag[i]==0) continue;
		int p=bian[i<<1].to,q=bian[(i<<1)-1].to;
		p=belong[p],q=belong[q];
		Add(p,q,++bianp);
		Add(q,p,++bianp);
		du[p]++,du[q]++;
	}
	memset(hash,0,sizeof(hash));
	Ans--;
	for(int i=1;i<=bep;i++)
	{
		if(hash[i]==0)
		{
			done(i);
			Ans++;
		}
	}
	Ans+=bianp/2+N-bep;
	for(int i=1;i<=bep;i++)
		if(du[i]==1)
			Ans--;
	cout<<Ans<<endl;
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

int N,M;
int hash[100010]={0};
struct bian_
{
	int to;
	int next;
}bian[200010]={{0,0}};
int First[2010]={0};
int dfn[2010]={0};
int dfsp=0;
int Low[2010]={0};
int flag[100010]={0};
int belong[2010]={0};
int bep=0;
int bianp=0;
int Mdist=0,pot=0;
int du[2010]={0};
int Ans=0;

void Add(int p,int q,int k)
{
	bian[k].to=q;
	bian[k].next=First[p];
	First[p]=k;
	return;
}

void dfs(int cnt)
{
	dfn[cnt]=++dfsp;
	Low[cnt]=dfn[cnt];
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		int u=bian[i].to;
		if(hash[(i+1)>>1]==1) continue;
		hash[(i+1)>>1]=1;
		if(dfn[u]==0)
		{
			dfs(u);
			Low[cnt]=min(Low[cnt],Low[u]);
			if(Low[u]==dfn[u])
				flag[(i+1)>>1]=1;
		}
		else Low[cnt]=min(Low[cnt],dfn[u]);
	}
	return;
}

void dfs2(int cnt)
{
	belong[cnt]=bep;
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		if(flag[(i+1)>>1]==1) continue;
		int u=bian[i].to;
		if(belong[u]!=0) continue;
		dfs2(u);
	}
	return;
}

void dfs3(int cnt,int fa,int dd)
{
	hash[cnt]=1;
	if(pot==0 || dd>Mdist)
		pot=cnt,Mdist=dd;
	for(int i=First[cnt];i!=0;i=bian[i].next)
	{
		int u=bian[i].to;
		if(u==fa) continue;
		dfs3(u,cnt,dd+1);
	}
	return;
}

void done(int X)
{
	Mdist=0,pot=0;
	dfs3(X,0,0);
	int O=pot;
	Mdist=pot=0;
	dfs3(O,0,0);
	if(Mdist>0) Ans-=Mdist-2;
	return;
}

int main()
{
	cin>>N>>M;
	for(int i=1;i<=M;i++)
	{
		int p,q;
		scanf("%d%d",&p,&q);
		if(p==q)
		{
			i--,M--;
			continue;
		}
		Add(p,q,(i<<1)-1);
		Add(q,p,i<<1);
	}
	for(int i=1;i<=N;i++)
	{
		if(dfn[i]==0)
			dfs(i);
	}
	for(int i=1;i<=N;i++)
	{
		if(belong[i]==0)
		{
			bep++;
			dfs2(i);
		}
	}
	memset(First,0,sizeof(First));
	for(int i=1;i<=M;i++)
	{
		if(flag[i]==0) continue;
		int p=bian[i<<1].to,q=bian[(i<<1)-1].to;
		p=belong[p],q=belong[q];
		if(p==q) continue;
		Add(p,q,++bianp);
		Add(q,p,++bianp);
		du[p]++,du[q]++;
	}
	memset(hash,0,sizeof(hash));
	Ans--;
	for(int i=1;i<=bep;i++)
	{
		if(hash[i]==0)
		{
			done(i);
			Ans++;
		}
	}
	Ans+=bianp/2+N-bep;
	for(int i=1;i<=bep;i++)
		if(du[i]==1)
			Ans--;
	cout<<Ans<<endl;
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10100, maxm = 610000 ;
int pre[maxm], now[maxm], son[maxm];
int n, m;
namespace Dinit{
	int Getchar(){
		int tmp = 0;
		char ch;
		while (ch = getchar()) if (ch >= '0' && ch <= '9') break;
		for (;ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
		return tmp;
	}
	int tot;
	void cc(int a, int b){
		pre[++tot] = now[a];
		now[a] = tot;
		son[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void init(){
		n = Getchar(), m = Getchar();
		for (int i = 1; i <= m; i ++){
			int a = Getchar(), b = Getchar();
			make(a, b);
		}
	}
}

bool ok[maxn];
namespace Dfind{
	int asd = 0, sign;
	int number[maxn];
	int dfn[maxn], num, sum, low[maxn], stack[maxn];
	bool instack[maxn];int ans;
	void dfs(int x, int fa){
		asd ++;
		dfn[x] = low[x] = ++sign;
		instack[x] = true;
		ok[x] = true;
		stack[++sum] = x;
		for (int p = now[x]; p; p = pre[p])
			if (son[p] != fa)
				if (!dfn[son[p]]){
					dfs(son[p], x);
					low[x] = min(low[son[p]], low[x]);
				}
				else
					if (instack[son[p]])
						low[x] = min(dfn[son[p]], low[x]);
		if (dfn[x] == low[x]){
			num ++;
			int asdaa = 0;
			while (stack[sum + 1] != x){
				instack[stack[sum]] = false;
				number[stack[sum]] = num;
				sum --;
				asdaa ++;
			}
			ans += asdaa - 1;
		}
	}
	int tot;
	int dist[maxn][2];
	int pre1[maxm], ru[maxn],now1[maxm], son1[maxm];
	void cc(int a, int b){
		ru[b] ++;
		pre1[++tot] = now1[a];
		now1[a] = tot;
		son1[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void make_edge(){
		for (int i = 1; i <= n; i ++)if (number[i])
				for (int p = now[i]; p; p = pre[p])
					if (number[i] != number[son[p]])
						if (number[i] <= number[son[p]])
							make(number[i], number[son[p]]);
	}
	void dfs1(int x, int fa){
		for (int p = now1[x]; p; p = pre1[p])
			if (son1[p] != fa){
				dfs1(son1[p], x);
				if (dist[son1[p]][0] + 1 > dist[x][0]){
					dist[x][0] = dist[son1[p]][0] + 1;
					dist[x][1] = dist[son1[p]][1];
				}
			}
		if (!dist[x][0]) dist[x][1] = x;
	}
	int find(int x){
		memset(now1, 0, sizeof(now1));
		memset(dist, 0, sizeof(dist));
		memset(number, 0, sizeof(number));
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(ru, 0, sizeof(ru));
		memset(instack, 0, sizeof(instack));
		tot = 0, num = 0,
		asd = 0, sign = 0;
		ans = 0;
		int point1 = 0;
		dfs(x, x);
		make_edge();
		dfs1(number[x], number[x]);
		point1 = dist[number[x]][1];
		memset(dist, 0, sizeof(dist));
		dfs1(point1, point1);

	//	cout <<ans <<' ' <<num <<' ' <<x << ' ' <<point1 <<' ' << dist[point1][0] <<endl;
		ans += num - dist[point1][0] + 1;

		for (int i = 1; i <= num; i ++)
			if (ru[i] == 1)
				ans --;
		return ans;
	}
}
namespace Dwork{
	void work(){
		int ans = 0;
		int tot = 0;
		for (int i = 1; i <= n; i ++)
			if (!ok[i]){
				ans += Dfind::find(i);
				tot ++;
			}
	//	cout <<ans <<' ' <<tot <<endl;
		printf("%d\n", ans + tot - 1);
	}
}

int main(){
	Dinit::init();
	Dwork::work();
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10100, maxm = 610000 ;
int pre[maxm], now[maxm], son[maxm];
int n, m;
namespace Dinit{
	int Getchar(){
		int tmp = 0;
		char ch;
		while (ch = getchar()) if (ch >= '0' && ch <= '9') break;
		for (;ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
		return tmp;
	}
	int tot;
	void cc(int a, int b){
		pre[++tot] = now[a];
		now[a] = tot;
		son[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void init(){
		n = Getchar(), m = Getchar();
		for (int i = 1; i <= m; i ++){
			int a = Getchar(), b = Getchar();
			make(a, b);
		}
	}
}

bool ok[maxn];
namespace Dfind{
	int asd = 0, sign;
	int number[maxn];
	int dfn[maxn], num, sum, low[maxn], stack[maxn];
	bool instack[maxn];int ans;
	void dfs(int x, int fa){
		asd ++;
		dfn[x] = low[x] = ++sign;
		instack[x] = true;
		ok[x] = true;
		stack[++sum] = x;
		for (int p = now[x]; p; p = pre[p])
			if (son[p] != fa)
				if (!dfn[son[p]]){
					dfs(son[p], x);
					low[x] = min(low[son[p]], low[x]);
				}
				else
					if (instack[son[p]])
						low[x] = min(dfn[son[p]], low[x]);
		if (dfn[x] == low[x]){
			num ++;
			int asdaa = 0;
			while (stack[sum + 1] != x){
				instack[stack[sum]] = false;
				number[stack[sum]] = num;
				sum --;
				asdaa ++;
			}
			ans += asdaa - 1;
		}
	}
	int tot;
	int dist[maxn][2];
	int pre1[maxm], ru[maxn],now1[maxm], son1[maxm];
	void cc(int a, int b){
		ru[b] ++;
		pre1[++tot] = now1[a];
		now1[a] = tot;
		son1[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void make_edge(){
		for (int i = 1; i <= n; i ++)if (number[i])
				for (int p = now[i]; p; p = pre[p])
					if (number[i] != number[son[p]])
						if (number[i] <= number[son[p]])
							make(number[i], number[son[p]]);
	}
	void dfs1(int x, int fa){
		for (int p = now1[x]; p; p = pre1[p])
			if (son1[p] != fa){
				dfs1(son1[p], x);
				if (dist[son1[p]][0] + 1 > dist[x][0]){
					dist[x][0] = dist[son1[p]][0] + 1;
					dist[x][1] = dist[son1[p]][1];
				}
			}
		if (!dist[x][0]) dist[x][1] = x;
	}
	int find(int x){
		memset(now1, 0, sizeof(now1));
		memset(dist, 0, sizeof(dist));
		memset(number, 0, sizeof(number));
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(ru, 0, sizeof(ru));
		memset(instack, 0, sizeof(instack));
		tot = 0, num = 0,
		asd = 0, sign = 0;
		ans = 0;
		int point1 = 0;
		dfs(x, x);
		make_edge();
		dfs1(number[x], number[x]);
		point1 = dist[number[x]][1];
		memset(dist, 0, sizeof(dist));
		dfs1(point1, point1);

	//	cout <<ans <<' ' <<x << ' ' <<point1 <<' ' << dist[point1][0] <<endl;
		ans = num - dist[point1][0] + 1;
		for (int i = 1; i <= num; i ++)
			if (ru[i] == 1)
				ans --;
		return ans;
	}
}
namespace Dwork{
	void work(){
		int ans = 0;
		int tot = 0;
		for (int i = 1; i <= n; i ++)
			if (!ok[i]){
				ans += Dfind::find(i);
				tot ++;
			}
		//cout <<ans <<' ' <<tot <<endl;
		printf("%d\n", ans + tot - 1);
	}
}

int main(){
	Dinit::init();
	Dwork::work();
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10100, maxm = 610000 ;
int pre[maxm], now[maxm], son[maxm];
int n, m;
namespace Dinit{
	int Getchar(){
		int tmp = 0;
		char ch;
		while (ch = getchar()) if (ch >= '0' && ch <= '9') break;
		for (;ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
		return tmp;
	}
	int tot;
	void cc(int a, int b){
		pre[++tot] = now[a];
		now[a] = tot;
		son[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void init(){
		n = Getchar(), m = Getchar();
		for (int i = 1; i <= m; i ++){
			int a = Getchar(), b = Getchar();
			make(a, b);
		}
	}
}

bool ok[maxn];
namespace Dfind{
	int asd = 0, sign;
	int number[maxn];
	int dfn[maxn], num, sum, low[maxn], stack[maxn];
	bool instack[maxn];
	void dfs(int x, int fa){
		asd ++;
		dfn[x] = low[x] = ++sign;
		instack[x] = true;
		ok[x] = true;
		stack[++sum] = x;
		for (int p = now[x]; p; p = pre[p])
			if (son[p] != fa)
				if (!dfn[son[p]]){
					dfs(son[p], x);
					low[x] = min(low[son[p]], low[x]);
				}
				else
					if (instack[son[p]])
						low[x] = min(dfn[son[p]], low[x]);
		if (dfn[x] == low[x]){
			num ++;
			while (stack[sum + 1] != x){
				instack[stack[sum]] = false;
				number[stack[sum]] = num;
				sum --;
			}
		}
	}
	int tot;
	int dist[maxn][2];
	int pre1[maxm], ru[maxn],now1[maxm], son1[maxm];
	void cc(int a, int b){
		ru[b] ++;
		pre1[++tot] = now1[a];
		now1[a] = tot;
		son1[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void make_edge(){
		for (int i = 1; i <= n; i ++)if (number[i])
				for (int p = now[i]; p; p = pre[p])
					if (number[i] != number[son[p]])
						if (number[i] <= number[son[p]])
							make(number[i], number[son[p]]);
	}
	void dfs1(int x, int fa){
		for (int p = now1[x]; p; p = pre1[p])
			if (son1[p] != fa){
				dfs1(son1[p], x);
				if (dist[son1[p]][0] + 1 > dist[x][0]){
					dist[x][0] = dist[son1[p]][0] + 1;
					dist[x][1] = dist[son1[p]][1];
				}
			}
		if (!dist[x][0]) dist[x][1] = x;
	}
	int find(int x){
		memset(now1, 0, sizeof(now1));
		memset(dist, 0, sizeof(dist));
		memset(number, 0, sizeof(number));
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(ru, 0, sizeof(ru));
		memset(instack, 0, sizeof(instack));
		tot = 0, num = 0,
		asd = 0, sign = 0;
		int point1 = 0;
		dfs(x, x);
		make_edge();
		dfs1(number[x], number[x]);
		point1 = dist[number[x]][1];
		memset(dist, 0, sizeof(dist));
		dfs1(point1, point1);
	//	cout <<x << ' ' <<point1 <<' ' << dist[point1][0] <<endl;
		int ans = asd - dist[point1][0] + 1;
		for (int i = 1; i <= num; i ++)
			if (ru[i] == 1)
				ans --;
		return ans;
	}
}
namespace Dwork{
	void work(){
		int ans = 0;
		int tot = 0;
		for (int i = 1; i <= n; i ++)
			if (!ok[i]){
				ans += Dfind::find(i);
				tot ++;
			}
	//	cout <<ans <<' ' <<tot <<endl;
		printf("%d\n", ans + tot - 1);
	}
}

int main(){
	Dinit::init();
	Dwork::work();
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int Getchar(){
    int tmp = 0 ;
    char ch;
    bool b = true;
    while (ch = getchar()){
        if (ch == '-') b = false;
        if ( ch >= '0' && ch <= '9' ) break;
    }
    for (; ch >= '0' && ch <='9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
    if (b)return tmp ;return tmp;
}
const int maxn = 2100, maxm = 210000 ;
int n, m, num;
int number[maxn];
int pre[maxm], now[maxn], son[maxm];
namespace Dprapare{
    int tot;
    void cc(int a, int b){
        pre[++tot] = now[a];
        now[a] = tot;
        son[tot] = b;
    }
    void make(int a,int b){ cc(a, b); cc(b, a); }
    void init(){
        n = Getchar(), m = Getchar();
        for (int i = 1; i <= m; i ++){
            int a = Getchar(), b = Getchar();
            make(a, b);
        }
    }

    int stack[maxn], sign, dfn[maxn], low[maxn];
    bool instack[maxn];
    void dfs(int x, int fa){
        dfn[x] = low[x] = ++sign;
        stack[++tot] = x;
        instack[x] = true;
        for (int p = now[x]; p; p = pre[p])if (son[p] != fa)
            if (!dfn[son[p]]){
                dfs(son[p], x);
                low[x] = min(low[x], low[son[p]]);
            }
            else if(instack[son[p]]) low[x] = min(low[x], dfn[son[p]]);
        if (low[x] == dfn[x]){
            num++;
            while (stack[tot + 1] != x){
                number[stack[tot]] = num;
                instack[stack[tot --]] = false;
            }
        }
    }
    void prapare(){
        init();
        dfs(1,1);
    }
}

namespace Dwork{
    int pre1[maxm], now1[maxn], son1[maxn];
    int du[maxn], ru[maxn], tot;
    void cc(int a, int b){
        pre1[++tot] = now1[a];
        now1[a] = tot;
        son1[tot] = b;
        ru[b]++;
    }
    bool bb[1500][1500];
    void make(int a, int b){cc(a, b), cc(b, a);}
    void make_edge(){
        for (int i = 1; i <= n; i ++)
            for (int p = now[i]; p; p = pre[p])
                if (number[i] != number[son[p]] && !bb[number[i]][number[son[p]]]){
                    make(number[i], number[son[p]]);
                    bb[number[i]][number[son[p]]] = bb[number[son[p]]][number[i]] = 1;
                }

    }
    int dist[maxn], next[maxn];
    void dfs(int x, int fa){
        for (int p = now1[x]; p; p = pre1[p])
            if (son1[p] != fa){
                dfs(son1[p], x);
                if (dist[son1[p]] + 1 > dist[x]){
                    dist[x] = dist[son1[p]] + 1;
                    if (next[son1[p]])
                        next[x] = next[son1[p]];
                    else next[x] = son1[p];
                }
            }
    }
    void work(){
        make_edge();
        dfs(1,1);
        int point1 = next[1];
        memset(dist, 0, sizeof(dist));
        dfs(point1, point1);
        int tot = 0, ans = n - dist[point1] + 1;
        for (int i = 1; i <= num; i ++)
            if (ru[i] == 1)
                ans --;
        printf("%d\n", ans);
    }
}
int main(){
    Dprapare::prapare();
    Dwork::work();
    return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10100, maxm = 610000 ;
int pre[maxm], now[maxm], son[maxm];
int n, m;
namespace Dinit{
	int Getchar(){
		int tmp = 0;
		char ch;
		while (ch = getchar()) if (ch >= '0' && ch <= '9') break;
		for (;ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
		return tmp;
	}
	int tot;
	void cc(int a, int b){
		pre[++tot] = now[a];
		now[a] = tot;
		son[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void init(){
		n = Getchar(), m = Getchar();
		for (int i = 1; i <= m; i ++){
			int a = Getchar(), b = Getchar();
			make(a, b);
		}
	}
}

bool ok[maxn];
namespace Dfind{
	int asd = 0, sign;
	int number[maxn];
	int dfn[maxn], num, sum, low[maxn], stack[maxn];
	bool instack[maxn];int ans;
	void dfs(int x, int fa){
		asd ++;
		dfn[x] = low[x] = ++sign;
		instack[x] = true;
		ok[x] = true;
		stack[++sum] = x;
		for (int p = now[x]; p; p = pre[p])
			if (son[p] != fa)
				if (!dfn[son[p]]){
					dfs(son[p], x);
					low[x] = min(low[son[p]], low[x]);
				}
				else
					if (instack[son[p]])
						low[x] = min(dfn[son[p]], low[x]);
		if (dfn[x] == low[x]){
			num ++;
			int asdaa = 0;
			while (stack[sum + 1] != x){
				instack[stack[sum]] = false;
				number[stack[sum]] = num;
				sum --;
				asdaa ++;
			}
			ans += asdaa - 1;
		}
	}
	int tot;
	int dist[maxn][2];
	int pre1[maxm], ru[maxn],now1[maxm], son1[maxm];
	void cc(int a, int b){
		ru[b] ++;
		pre1[++tot] = now1[a];
		now1[a] = tot;
		son1[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void make_edge(){
		for (int i = 1; i <= n; i ++)if (number[i])
				for (int p = now[i]; p; p = pre[p])
					if (number[i] != number[son[p]])
						if (number[i] <= number[son[p]])
							make(number[i], number[son[p]]);
	}
	void dfs1(int x, int fa){
		for (int p = now1[x]; p; p = pre1[p])
			if (son1[p] != fa){
				dfs1(son1[p], x);
				if (dist[son1[p]][0] + 1 > dist[x][0]){
					dist[x][0] = dist[son1[p]][0] + 1;
					dist[x][1] = dist[son1[p]][1];
				}
			}
		if (!dist[x][0]) dist[x][1] = x;
	}
	int find(int x){
		memset(now1, 0, sizeof(now1));
		memset(dist, 0, sizeof(dist));
		memset(number, 0, sizeof(number));
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(ru, 0, sizeof(ru));
		memset(instack, 0, sizeof(instack));
		tot = 0, num = 0,
		asd = 0, sign = 0;
		ans = 0;
		int point1 = 0;
		dfs(x, x);
		make_edge();
		dfs1(number[x], number[x]);
		point1 = dist[number[x]][1];
		memset(dist, 0, sizeof(dist));
		dfs1(point1, point1);

		if (num == 1) return ans;
		ans += num - dist[point1][0] + 1;

		for (int i = 1; i <= num; i ++)
			if (ru[i] <= 1)
				ans --;
		return ans;
	}
}
namespace Dwork{
	void work(){
		int ans = 0;
		int tot = 0;
		for (int i = 1; i <= n; i ++)
			if (!ok[i]){
				ans += Dfind::find(i);
				tot ++;
			}
		//cout <<ans <<' ' <<tot <<endl;
		printf("%d\n", ans + tot - 1);
	}
}

int main(){
	Dinit::init();
	Dwork::work();
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10100, maxm = 610000 ;
int pre[maxm], now[maxm], son[maxm];
int n, m;
namespace Dinit{
	int Getchar(){
		int tmp = 0;
		char ch;
		while (ch = getchar()) if (ch >= '0' && ch <= '9') break;
		for (;ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
		return tmp;
	}
	int tot;
	void cc(int a, int b){
		pre[++tot] = now[a];
		now[a] = tot;
		son[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void init(){
		n = Getchar(), m = Getchar();
		for (int i = 1; i <= m; i ++){
			int a = Getchar(), b = Getchar();
			make(a, b);
		}
	}
}

bool ok[maxn];
namespace Dfind{
	int asd = 0, sign;
	int number[maxn];
	int dfn[maxn], num, sum, low[maxn], stack[maxn];
	bool instack[maxn];
	void dfs(int x, int fa){
		asd ++;
		dfn[x] = low[x] = ++sign;
		instack[x] = true;
		ok[x] = true;
		stack[++sum] = x;
		for (int p = now[x]; p; p = pre[p])
			if (son[p] != fa)
				if (!dfn[son[p]]){
					dfs(son[p], x);
					low[x] = min(low[son[p]], low[x]);
				}
				else
					if (instack[son[p]])
						low[x] = min(dfn[son[p]], low[x]);
		if (dfn[x] == low[x]){
			num ++;
			while (stack[sum + 1] != x){
				instack[stack[sum]] = false;
				number[stack[sum]] = num;
				sum --;
			}
		}
	}
	int tot;
	int pre1[maxm], ru[maxn],now1[maxm], son1[maxm];
	void cc(int a, int b){
		ru[b] ++;
		pre1[++tot] = now1[a];
		now1[a] = tot;
		son1[tot] = b;
	}
	void make(int a, int b){
		cc(a, b);
		cc(b, a);
	}
	void make_edge(){
		for (int i = 1; i <= n; i ++)if (number[i])
				for (int p = now[i]; p; p = pre[p])
					if (number[i] != number[son[p]])
						if (number[i] <= number[son[p]])
							make(number[i], number[son[p]]);
	}
	int dist[maxn][2];
	void dfs1(int x, int fa){
		for (int p = now1[x]; p; p = pre1[p])
			if (son1[p] != fa){
				dfs1(son1[p], x);
				if (dist[son1[p]][0] + 1 > dist[x][0]){
					dist[x][0] = dist[son1[p]][0] + 1;
					dist[x][1] = dist[son1[p]][1];
				}
			}
		if (!dist[x][0]) dist[x][1] = x;
	}
	int find(int x){
		memset(now1, 0, sizeof(now1));
		memset(dist, 0, sizeof(dist));
		memset(number, 0, sizeof(number));
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(ru, 0, sizeof(ru));
		memset(instack, 0, sizeof(instack));
		tot = 0, num = 0,
		asd = 0, sign = 0;
		int point1 = 0;
		dfs(x, x);
		make_edge();
		dfs1(x, x);
		point1 = dist[x][1];
		memset(dist, 0, sizeof(dist));
		dfs1(point1, point1);
		int ans = asd - dist[point1][0] + 1;
		for (int i = 1; i <= n; i ++)
			if (ru[i] == 1)
				ans --;
		return ans;
	}
}
namespace Dwork{
	void work(){
		int ans = 0;
		int tot = 0;
		for (int i = 1; i <= n; i ++)
			if (!ok[i]){
				ans += Dfind::find(i);
				tot ++;
			}
		printf("%d\n", ans + tot - 1);
	}
}

int main(){
	Dinit::init();
	Dwork::work();
	return 0;
}


#include<iostream>
#include<vector>
using namespace std;
int n,m,stk[2001],DFS,top,f[2001],N,Dfn[2001],lv,ans,ml,x,y;
vector<int>Y[2001],E[2001];
int Tarjan(int F,int X)
{
	if(Dfn[X])return Dfn[X];
	int low=Dfn[X]=++DFS;
	stk[++top]=X;
	for(int i=0;i<Y[X].size();++i)if(Y[X][i]!=F)low=min(low,Tarjan(X,Y[X][i]));
	if(low==Dfn[X])
	for(++N;;)
	{
		f[stk[top]]=N;
		if(stk[top--]==X)break;
	}
	return low;
}

int Dfs(int F,int X)
{

	Dfn[X]=1;
	int m1=0,m2=0,tmp;
	if(E[X].size()<2)lv++;
	for(int i=0;i<E[X].size();++i)
	if(E[X][i]!=F)
		if((tmp=Dfs(X,E[X][i]))>m1)m2=m1,m1=tmp;else if(tmp>m2)m2=tmp;
	ml=max(ml,m1+m2+1);
	return m1+1;
}

int main()
{
	//freopen("cirno.in","rb",stdin);
	//freopen("cirno.out","wb",stdout);
	cin>>n>>m;
	for(;m--;)
	{
		cin>>x>>y;
		Y[x].push_back(y);
		Y[y].push_back(x);
	}
	for(int i=1;i<=n;++i)Tarjan(0,i);
	for(int i=1;i<=n;++i)
		for(int j=0;j<Y[i].size();++j)
			if(f[Y[i][j]]==f[i])continue;else
				E[f[i]].push_back(f[Y[i][j]]);
	memset(Dfn,0,sizeof Dfn);
	for(int i=1;i<=N;++i)if(!Dfn[i])
	{
		ml=lv=0;
		Dfs(0,i);
		ans-=ml+lv-3;
		if(ml==1&&lv==1)ans++;
	}
	printf("%d\n",ans-1+n);
	return 0;
}
/*
void read(int &X)
{
	char ch;
	while(ch=getchar(),ch<'0');
	X=ch-'0';
	while(ch=getchar(),ch>='0')x=x*10+ch-'0';
}
*/


#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int n,m,stk[2001],DFS,top,f[2001],N,Dfn[2001],lv,ans,ml,x,y;
vector<int>Y[2001],E[2001];
int Tarjan(int F,int X)
{
	if(Dfn[X])return Dfn[X];
	int low=Dfn[X]=++DFS;
	stk[++top]=X;
	for(int i=0;i<Y[X].size();++i)if(Y[X][i]!=F)low=min(low,Tarjan(X,Y[X][i]));
	if(low==Dfn[X])
	for(++N;;)
	{
		f[stk[top]]=N;
		if(stk[top--]==X)break;
	}
	return low;
}

int Dfs(int F,int X)
{

	Dfn[X]=1;
	int m1=0,m2=0,tmp;
	if(E[X].size()<2)lv++;
	for(int i=0;i<E[X].size();++i)
	if(E[X][i]!=F)
		if((tmp=Dfs(X,E[X][i]))>m1)m2=m1,m1=tmp;else if(tmp>m2)m2=tmp;
	ml=max(ml,m1+m2+1);
	return m1+1;
}

int main()
{
	//freopen("cirno.in","rb",stdin);
	//freopen("cirno.out","wb",stdout);
	cin>>n>>m;
	for(;m--;)
	{
		cin>>x>>y;
		Y[x].push_back(y);
		Y[y].push_back(x);
	}
	for(int i=1;i<=n;++i)Tarjan(0,i);
	for(int i=1;i<=n;++i)
		for(int j=0;j<Y[i].size();++j)
			if(f[Y[i][j]]==f[i])continue;else
				E[f[i]].push_back(f[Y[i][j]]);
	memset(Dfn,0,sizeof Dfn);
	for(int i=1;i<=N;++i)if(!Dfn[i])
	{
		ml=lv=0;
		Dfs(0,i);
		ans-=ml+lv-3;
		if(ml==1&&lv==1)ans--;
	}
	cout<<ans-1+n;
	return 0;
}
/*
void read(int &X)
{
	char ch;
	while(ch=getchar(),ch<'0');
	X=ch-'0';
	while(ch=getchar(),ch>='0')x=x*10+ch-'0';
}
*/


#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int n,m,stk[2001],DFS,top,f[2001],N,Dfn[2001],lv,ans,ml,x,y;
vector<int>Y[2001],E[2001];
int Tarjan(int F,int X)
{
	if(Dfn[X])return Dfn[X];
	int low=Dfn[X]=++DFS;
	stk[++top]=X;
	for(int i=0;i<Y[X].size();++i)if(Y[X][i]!=F)low=min(low,Tarjan(X,Y[X][i]));
	if(low==Dfn[X])
	for(++N;;)
	{
		f[stk[top]]=N;
		if(stk[top--]==X)break;
	}
	return low;
}

int Dfs(int F,int X)
{

	Dfn[X]=1;
	int m1=0,m2=0,tmp;
	if(E[X].size()<2)lv++;
	for(int i=0;i<E[X].size();++i)
	if(E[X][i]!=F)
		if((tmp=Dfs(X,E[X][i]))>m1)m2=m1,m1=tmp;else if(tmp>m2)m2=tmp;
	ml=max(ml,m1+m2+1);
	return m1+1;
}

int main()
{
	//freopen("cirno.in","rb",stdin);
	//freopen("cirno.out","wb",stdout);
	cin>>n>>m;
	for(;m--;)
	{
		cin>>x>>y;
		Y[x].push_back(y);
		Y[y].push_back(x);
	}
	for(int i=1;i<=n;++i)Tarjan(0,i);
	for(int i=1;i<=n;++i)
		for(int j=0;j<Y[i].size();++j)
			if(f[Y[i][j]]==f[i])continue;else
				E[f[i]].push_back(f[Y[i][j]]);
	memset(Dfn,0,sizeof Dfn);
	for(int i=1;i<=N;++i)if(!Dfn[i])
	{
		ml=lv=0;
		Dfs(0,i);
		ans-=ml+lv-3;
		if(ml==1&&lv==1)ans++;
	}
	cout<<ans-1+n;
	return 0;
}
/*
void read(int &X)
{
	char ch;
	while(ch=getchar(),ch<'0');
	X=ch-'0';
	while(ch=getchar(),ch>='0')x=x*10+ch-'0';
}
*/


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

const int mi = 19931117;
const int N = 2010, M = 100010;
int dp[N], dp2[N], cnt[N], pa[N], tot, res;

int hd[N], to[M], nxt[M], mr;
inline void init (void)
{
	memset(hd, -1, sizeof hd);
	mr = 0;
}
inline void link (int a, int b)
{
	to[mr] = b, nxt[mr] = hd[a]; hd[a] = mr++;
}

int dfn[N], low[N], dfsidx = 0;
int stack[N], top = 0;
typedef pair<int, int> pii;
#define X first
#define Y second
vector<pii> bridge;
int bcc[N], bccidx = 0;

void tarjan (int idx, int pere)
{
	dfn[idx] = low[idx] = dfsidx++;
	stack[top++] = idx;
	for (int p = hd[idx]; p != -1; p = nxt[p])
	{
		int tar = to[p];
		if (tar == pere) continue;
		else if (dfn[tar] == -1)
		{
			tarjan(tar, idx);
			low[idx] = min(low[idx], low[tar]);
			if (low[tar] > dfn[idx])
			{
				bridge.push_back(pii(idx, tar));
				int t; do
				{
					t = stack[--top];
					bcc[t] = bccidx;

					// printf("BCC %d : %d\n", t + 1, bccidx);

				} while (t != tar);
				bccidx++;
			}
		}
		else low[idx] = min(low[idx], dfn[tar]);
	}
}
vector<int> member;
void treeinit (int x)
{
	// printf("TREEINIT: %d\n", x);
	cnt[x] = 1;
	member.push_back(x);
	for (int p = hd[x]; p != -1; p = nxt[p]) if (to[p] != pa[x])
	{
		pa[to[p]] = x;
		treeinit(to[p]);
		cnt[x] += cnt[to[p]];
	}
	// printf("TREE %d : CNT = %d\n", x, cnt[x]);
}
int sch[N];
void treedp (int x)
{
	dp[x] = 0, dp2[x] = 0, cnt[x] = 1;
	int m0 = 0, m1 = 0;
	for (int p = hd[x]; p != -1; p = nxt[p]) if (!sch[to[p]])
	{
		sch[to[p]] = true;
		treedp(to[p]);

		cnt[x] += cnt[to[p]];
		int tr = min(cnt[to[p]] - 1, dp2[to[p]] + 1);
		dp[x] += tr;
		if (cnt[to[p]] > 1) dp2[x] += dp2[to[p]] + 1;

		int trs = tr - dp[to[p]];
		if (trs > m0) m1 = m0, m0 = trs;
		else if (trs > m1) m1 = trs;
	}
	dp[x] -= m0;
	if (cnt[x] == tot)
	{
		res = min(res, dp[x]);
	}
	// printf("TREEDP %d: DP = %d, RES -> %d\n", x, dp[x], res);
}

int main ()
{
	int n, m; scanf("%d %d", &n, &m);
	init();
	for (int i = 0; i < m; i++)
	{
		int x, y; scanf("%d %d", &x, &y);
		link(x - 1, y - 1), link(y - 1, x - 1);
	}
	memset(dfn, -1, sizeof dfn);
	for (int i = 0; i < n; i++) if (dfn[i] == -1)
	{
		tarjan(i, -1);
		while (top)
		{
			bcc[stack[--top]] = bccidx;
			// printf("BCC %d : %d\n", stack[top] + 1, bccidx);
		}
		++bccidx;
	}
	init();
	for (vector<pii>::iterator ite = bridge.begin(); ite != bridge.end(); ++ite)
	{
		link(bcc[ite->X], bcc[ite->Y]), link(bcc[ite->Y], bcc[ite->X]);
		// printf("BRIDGE: BCC %d - BCC %d\n", bcc[ite->X], bcc[ite->Y]);
	}
	int ans = n - bccidx;
	memset(pa, -1, sizeof pa);
	for (int i = 0; i < bccidx; i++) if (pa[i] == -1)
	{
		member.clear();
		++ans;
		res = mi;
		treeinit(i), tot = cnt[i];
		for (vector<int>::iterator ite = member.begin(); ite != member.end(); ++ite)
		{
			memset(sch, 0, sizeof sch);
			sch[*ite] = true;
			// printf("ROOT: %d\n", *ite);
			treedp(*ite);
		}
		ans += res;
	}
	printf("%d\n", ans - 1);
	// system("pause");
	return 0;
}


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

const int mi = 19931117;
const int N = 2010, M = 400010;
int dp[N], dp2[N], cnt[N], pa[N], tot, res;

int hd[N], to[M], nxt[M], mr;
inline void init (void)
{
	memset(hd, -1, sizeof hd);
	mr = 0;
}
inline void link (int a, int b)
{
	to[mr] = b, nxt[mr] = hd[a]; hd[a] = mr++;
}

int dfn[N], low[N], dfsidx = 0;
int stack[N], top = 0;
typedef pair<int, int> pii;
#define X first
#define Y second
vector<pii> bridge;
int bcc[N], bccidx = 0;

void tarjan (int idx, int pere)
{
	dfn[idx] = low[idx] = dfsidx++;
	stack[top++] = idx;
	for (int p = hd[idx]; p != -1; p = nxt[p])
	{
		int tar = to[p];
		if (tar == pere) continue;
		else if (dfn[tar] == -1)
		{
			tarjan(tar, idx);
			low[idx] = min(low[idx], low[tar]);
			if (low[tar] > dfn[idx])
			{
				bridge.push_back(pii(idx, tar));
				int t; do
				{
					t = stack[--top];
					bcc[t] = bccidx;

					// printf("BCC %d : %d\n", t + 1, bccidx);

				} while (t != tar);
				bccidx++;
			}
		}
		else low[idx] = min(low[idx], dfn[tar]);
	}
}
vector<int> member;
void treeinit (int x)
{
	// printf("TREEINIT: %d\n", x);
	cnt[x] = 1;
	member.push_back(x);
	for (int p = hd[x]; p != -1; p = nxt[p]) if (to[p] != pa[x])
	{
		pa[to[p]] = x;
		treeinit(to[p]);
		cnt[x] += cnt[to[p]];
	}
	// printf("TREE %d : CNT = %d\n", x, cnt[x]);
}
int sch[N];
void treedp (int x)
{
	dp[x] = 0, dp2[x] = 0, cnt[x] = 1;
	int m0 = 0, m1 = 0;
	for (int p = hd[x]; p != -1; p = nxt[p]) if (!sch[to[p]])
	{
		sch[to[p]] = true;
		treedp(to[p]);

		cnt[x] += cnt[to[p]];
		int tr = min(cnt[to[p]] - 1, dp2[to[p]] + 1);
		dp[x] += tr;
		if (cnt[to[p]] > 1) dp2[x] += dp2[to[p]] + 1;

		int trs = tr - dp[to[p]];
		if (trs > m0) m1 = m0, m0 = trs;
		else if (trs > m1) m1 = trs;
	}
	dp[x] -= m0;
	if (cnt[x] == tot)
	{
		res = min(res, dp[x]);
	}
	// printf("TREEDP %d: DP = %d, RES -> %d\n", x, dp[x], res);
}

int main ()
{
	int n, m; scanf("%d %d", &n, &m);
	init();
	for (int i = 0; i < m; i++)
	{
		int x, y; scanf("%d %d", &x, &y);
		link(x - 1, y - 1), link(y - 1, x - 1);
	}
	memset(dfn, -1, sizeof dfn);
	for (int i = 0; i < n; i++) if (dfn[i] == -1)
	{
		tarjan(i, -1);
		while (top)
		{
			bcc[stack[--top]] = bccidx;
			// printf("BCC %d : %d\n", stack[top] + 1, bccidx);
		}
		++bccidx;
	}
	init();
	for (vector<pii>::iterator ite = bridge.begin(); ite != bridge.end(); ++ite)
	{
		link(bcc[ite->X], bcc[ite->Y]), link(bcc[ite->Y], bcc[ite->X]);
		// printf("BRIDGE: BCC %d - BCC %d\n", bcc[ite->X], bcc[ite->Y]);
	}
	int ans = n - bccidx;
	memset(pa, -1, sizeof pa);
	for (int i = 0; i < bccidx; i++) if (pa[i] == -1)
	{
		member.clear();
		++ans;
		res = mi;
		treeinit(i), tot = cnt[i];
		for (vector<int>::iterator ite = member.begin(); ite != member.end(); ++ite)
		{
			memset(sch, 0, sizeof sch);
			sch[*ite] = true;
			// printf("ROOT: %d\n", *ite);
			treedp(*ite);
		}
		ans += res;
	}
	printf("%d\n", ans - 1);
	// system("pause");
	return 0;
}


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

const int mi = 19931117;
const int N = 2010, M = 100010;
int dp[N], cnt[N], pa[N], tot, res;

int hd[N], to[M], nxt[M], mr;
inline void init (void)
{
	memset(hd, -1, sizeof hd);
	mr = 0;
}
inline void link (int a, int b)
{
	to[mr] = b, nxt[mr] = hd[a]; hd[a] = mr++;
}

int dfn[N], low[N], dfsidx = 0;
int stack[N], top = 0;
typedef pair<int, int> pii;
#define X first
#define Y second
vector<pii> bridge;
int bcc[N], bccidx = 0;

void tarjan (int idx, int pere)
{
	dfn[idx] = low[idx] = dfsidx++;
	stack[top++] = idx;
	for (int p = hd[idx]; p != -1; p = nxt[p])
	{
		int tar = to[p];
		if (tar == pere) continue;
		else if (dfn[tar] == -1)
		{
			tarjan(tar, idx);
			low[idx] = min(low[idx], low[tar]);
			if (low[tar] > dfn[idx])
			{
				bridge.push_back(pii(idx, tar));
				int t; do
				{
					t = stack[--top];
					bcc[t] = bccidx;

					// printf("BCC %d : %d\n", t, bccidx);

				} while (t != tar);
				bccidx++;
			}
		}
		else low[idx] = min(low[idx], dfn[tar]);
	}
}
void treeinit (int x)
{
	// printf("TREEINIT: %d\n", x);
	cnt[x] = 1;
	for (int p = hd[x]; p != -1; p = nxt[p]) if (to[p] != pa[x])
	{
		pa[to[p]] = x;
		treeinit(to[p]);
		cnt[x] += cnt[to[p]];
	}
	// printf("TREE %d : CNT = %d\n", x, cnt[x]);
}
void treedp (int x)
{
	dp[x] = 0;
	for (int p = hd[x]; p != -1; p = nxt[p]) if (to[p] != pa[x])
		dp[x] += cnt[to[p]] - 1;
	int m0 = 0, m1 = 0;
	for (int p = hd[x]; p != -1; p = nxt[p]) if (to[p] != pa[x])
	{
		treedp(to[p]);
		int trs = (cnt[to[p]] - 1) - dp[to[p]];
		if (trs > m0) m1 = m0, m0 = trs;
		else if (trs > m1) m1 = trs;
	}
	res = min(res, dp[x] - m0 - m1 + max(tot - cnt[x] - 1, 0));
	dp[x] -= m0;
	// printf("TREEDP %d: DP = %d, RES -> %d\n", x, dp[x], res);
}

int main ()
{
	int n, m; scanf("%d %d", &n, &m);
	init();
	for (int i = 0; i < m; i++)
	{
		int x, y; scanf("%d %d", &x, &y);
		link(x - 1, y - 1), link(y - 1, x - 1);
	}
	memset(dfn, -1, sizeof dfn);
	for (int i = 0; i < n; i++) if (dfn[i] == -1)
	{
		tarjan(i, -1);
		while (top)
		{
			bcc[stack[--top]] = bccidx;
			// printf("BCC %d : %d\n", stack[top], bccidx);
		}
		++bccidx;
	}
	init();
	for (vector<pii>::iterator ite = bridge.begin(); ite != bridge.end(); ++ite)
	{
		link(bcc[ite->X], bcc[ite->Y]), link(bcc[ite->Y], bcc[ite->X]);
		// printf("BRIDGE: BCC %d - BCC %d\n", bcc[ite->X], bcc[ite->Y]);
	}
	int ans = n - bccidx;
	memset(pa, -1, sizeof pa);
	for (int i = 0; i < bccidx; i++) if (pa[i] == -1)
	{
		++ans;
		res = mi;
		treeinit(i), tot = cnt[i], treedp(i);
		ans += res;
	}
	printf("%d\n", ans - 1);
	// system("pause");
	return 0;
}


#include <iostream>
#include <cstring>
#include <string>
using namespace std;

const size_t maxn = 51;
struct cnode
{
    long a, b, c;
};

int lena, lenb, n;
int a[maxn], b[maxn];
long long markA[maxn][maxn], markB[maxn][maxn];
cnode g[maxn];
int f[maxn][maxn];

int init()
{
    string sta, stb;
    cin >> sta >> stb;
    lena = sta.length();
    lenb = stb.length();
    for (int i = 0; i != lena; i++)
        a[i+1] = sta[i] - 'a';
    for (int i = 0; i != lenb; i++)
        b[i+1] = stb[i] - 'a';
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> sta;
        g[i].a = 1LL << (sta[0]-'a');
        g[i].b = 1LL << (sta[3]-'a');
        g[i].c = 1LL << (sta[4]-'a');
    }
    return 0;
}

int prework()
{
    memset(markA, 0, sizeof(markA));
    memset(markB, 0, sizeof(markB));
    for (int i = 1; i <= lena; i++)
        markA[i][i] |= 1LL << a[i];
    for (int c = 1; c != lena; c++)
        for (int i = 1; i + c <= lena; i++) {
            int j = i+c;
            for (int k = i; k != j; k++)
                for (int w = 1; w <= n; w++)
                    if ((markA[i][k] & g[w].b)&&(markA[k+1][j] & g[w].c))
                        markA[i][j] |= g[w].a;
        }
    for (int i = 1; i <= lenb; i++)
        markB[i][i] |= 1LL << b[i];
    for (int c = 1; c != lenb; c++)
        for (int i = 1; i + c <= lenb; i++) {
            int j = i+c;
            for (int k = i; k != j; k++)
                for (int w = 1; w <= n; w++)
                    if ((markB[i][k] & g[w].b)&&(markB[k+1][j] & g[w].c))
                        markB[i][j] |= g[w].a;
        }
    return 0;
}

int work()
{
    memset(f, maxn, sizeof(f));
    f[0][0] = 0;
    for (int i = 1; i <= lena; i++)
        for (int j = 1; j <= lenb; j++)
            for (int a = 1; a <= i; a++)
                for (int b = 1; b <= j; b++)
                    if (markA[a][i] & markB[b][j])
                        f[i][j] = min(f[i][j], f[a-1][b-1] + 1);
    if (f[lena][lenb]>=maxn) cout << "-1" << endl;
    else cout << f[lena][lenb] << endl;

    cin >> f[0][0];

    return 0;
}

int main()
{
    init();
    prework();
    work();
    return 0;
}