/*
http://poj.org/problem?id=3041
一个N*N的表格,表格中有一些asteroid,weapon 每次开炮能清除一行或者一列的asteroid
求最少的开炮次数
建模:若存在点(u,v),则建一条从u到v的有向路
容易看出,这是一个二分图,每一条边表示表格中的一个点
问题转换为:求最少的点,使得每条边都能被这些点匹配到
也就是一个最小点覆盖的问题,那么有一个结论是:最小点覆盖=最大匹配
我们只需要求最大的匹配数即可
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std;
const int INF=(1<<31)-1;
const double EPS=1e-8;
const int N=510;
int n,m,k;// X集合有n个点,Y集合有m个点,二分图中有k条边
bool path[N][N];// p[i][j]表示X集合中的点i到Y集合中的点j是否有路
int mate_x[N];// mate_x[i]表示X集合中的i在Y中匹配的点,初始为-1 ,每次都从X集合开始进行增广路的查找
int mate_y[N];// mate_y[i]表示Y集合中的i在X中匹配的点 ,初始为-1
int visited[N];// 每次从集合X中的点开始增广路的查找,所以用visited来记录“本次增广路查找”,Y集合中的i是否被匹配
int find(int u)
{
for(int v=1;v<=m;v++)//查找Y集合中的点
if(!visited[v]&&path[u][v])//Y中的v还未进行搜索,并且u到v有路
{
visited[v]=true; // 无论能否找到增广路,标记v在本次查找中已经被访问了
if(mate_y[v]==-1||find(mate_y[v]))
/*
1。 v还未被匹配(递归出口)
2。 v已经被匹配,并且能从v所匹配的点,查找到一条增广路
3。 重新标记v的匹配为u,u的匹配为v(即把增广路取反)
*/
{
mate_y[v]=u;
mate_x[u]=v;
return 1;
}
}
return 0;
}
int main()
{
while(cin>>n>>k)
{
m=n;
int u,v;
memset(path,false,sizeof(path));
while(k--)
{
scanf("%d %d",&u,&v);
path[u][v]=true;
}
int ans=0;
memset(mate_x,-1,sizeof(mate_x));
memset(mate_y,-1,sizeof(mate_y));
for(u=1;u<=n;u++)
{
memset(visited,false,sizeof(visited));
if(mate_x[u]==-1&&find(u))ans++;
}
printf("%d/n",ans);
}
return 0;
}