#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second

#define DUMP(x) cout<<#x<<":"<<(x)<<endl
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class T>
istream& operator>>(istream& is, vector<T>& xs){
  for(auto& x: xs)
	is >> x;
  return is;
}
template<class S, class T>
ostream& operator<<(ostream& os, const pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
ostream& operator<<(ostream& os, const vector<T>& xs){
  for(unsigned int i=0;i<xs.size();++i)
	os << (i?" ":"") << xs[i];
  return os;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}


const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;


/**
 * 与えられるグラフを下の形式で2部グラフに分ける
 */
bool mkbigraph(VVI& G, VVI& biG, int& M1, int& M2){
  int N = SZ(G), sz = 0;
  VI col(N, -1);
  REP(i,N){
	if(col[i] != -1) continue;
	queue<int> q;
	q.push(i);
	col[i] = 0;
	++sz;
	while(!q.empty()){
	  int u = q.front();
	  q.pop();
	  for(int to: G[u]){
		if(col[to] == -1){
		  col[to] = col[u] ^ 1;
		  q.push(to);
		  if(col[to] == 0) ++sz;
		}
		else if(col[to] == col[u]){
		  return false;
		}
	  }
	}
  }

  VI id(N, -1);
  biG.resize(sz);
  M1 = M2 = 0;
  REP(i,N){
	if(id[i] == -1) id[i] = M1++;
	if(col[i] != 0) continue;
	
	for(int to: G[i]){
	  if(col[to] == 0) continue;
	  if(id[to] == -1) id[to] = M2++;
	  biG[i].PB(id[to]);
	}
  }

  return true;
}

/* Hopcroft–Karp Algorithm
 * O(V E^0.5)
 *
 * 二部グラフ G = U \cup V とすると
 * N == SZ(G) == SZ(U) == SZ(matchU)
 * M == SZ(matchV) == SZ(V)
 * かつ V={0,1,...,N-1}, U={0,1,...,M-1}となっていて
 * Gには U -> V の辺のみ含むこと
 * ref https://brilliant.org/wiki/hopcroft-karp/
 */
int bipartite_matching(VVI& G, VI& matchU, VI& matchV){
  int N = G.size();
  fill(ALL(matchU), -1);
  fill(ALL(matchV), -1);
  vector<int> level(N);
  vector<bool> finished(N);

  int total = 0;
  for(bool up=true;up;){
	up = false;

	// bfs
	fill(ALL(level), -1);
    queue<int> Q;
	REP(i,N){
	  if(matchU[i] == -1){
		level[i] = 0;
		Q.push(i);
	  }
	}
	while(!Q.empty()){
      int u = Q.front();
	  Q.pop();
      for(auto to: G[u]){
		if(matchV[to] != -1 && level[matchV[to]] == -1){
		  level[matchV[to]] = level[u] + 1;
		  Q.push(matchV[to]);
		}
	  }
    }

	// dfs
	fill(ALL(finished), false);
	function<bool(int)> dfs = [&](int u){
	  finished[u] = true;
	  for(auto to: G[u]){
		int bk = matchV[to];
		if(bk == -1 || (!finished[bk] && level[bk] == level[u]+1 && dfs(bk))){
		  matchU[u] = to;
		  matchV[to] = u;
		  return true;
		}
	  }
	  return false;
	};


	REP(i,N){
	  if(matchU[i] == -1 && dfs(i)){
		up = true;
		++total;
	  }
    }
  }
  return total;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int X, Y, E;
  cin >> X >> Y >> E;
  VVI G(X+Y);
  REP(i,E){
	int x, y;
	cin >> x >> y;
	G[x].PB(X+y);
	G[X+y].PB(x);
  }
  int M1, M2;
  VVI biG;
  mkbigraph(G, biG, M1, M2);
  VI mu(M1), mv(M2);
  cout << bipartite_matching(biG, mu, mv) << endl;

  return 0;
}



Measured memory_bytes: 3376