#include <cstdio>  //{{{
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <algorithm>

#define ALL(c) (c).begin(), (c).end()
#define DUMP(x) std::cerr << #x << ':' << x << '\n';

typedef long long ll;
// clang-format off
template<typename T,typename U>inline bool chmax(T&x,U a){if(x>=a)return 0;x=a;return 1;}
template<typename T,typename U>inline bool chmin(T&x,U a){if(x<=a)return 0;x=a;return 1;}
inline int in(){int x;scanf("%d", &x);return x;}
// clang-format on
// }}}
//{{{ graph.hpp
#ifndef INCLUDE_GRAPH_HPP
#define INCLUDE_GRAPH_HPP
#include <vector>
#include <climits>
namespace orliv {
namespace graph {
struct Edge {
  typedef int weight_type;
  static constexpr weight_type INF =
      std::numeric_limits<weight_type>::max() - 100;

  int from, to;
  weight_type w;
  Edge(int from, int to, weight_type w = 1) : from(from), to(to), w(w) {}
  bool operator<(const Edge& rhs) const {
    if (w != rhs.w) return w > rhs.w;
    if (from != rhs.from) return from < rhs.from;
    return to < rhs.to;
  }
};

typedef Edge::weight_type Weight;
typedef std::vector<Edge> Edges;
typedef std::vector<Weight> Weights;
typedef std::vector<int> Path;
typedef std::vector<int> Nodes;
}
typedef std::vector<graph::Edges> Graph;
}
#endif
//}}}
// {{{ dinic.cc
// verify AOJ GRL_6_A
#ifndef INCLUDE_GRAPH_HPP
#include "graph.hpp"
#endif
#include <queue>

namespace orliv {
namespace graph {
struct Dinic {
  struct REdge {
    int rev;
    int to;
    int from;
    Edge::weight_type cap;
    REdge(const Edge& edge, int rev)
        : rev(rev), to(edge.to), from(edge.from), cap(edge.w) {}
  };
  typedef std::vector<REdge> REdges;
  typedef std::vector<REdges> RGraph;
  RGraph G;
  std::vector<int> level, iter;

  Dinic(int V) : G(V), level(V), iter(V) {}

  template <typename... Types>
  void add(Types... args) {
    Edge e(std::forward<Types>(args)...);
    G[e.from].emplace_back(e, G[e.to].size());
    Edge r(e.to, e.from, 0);
    G[r.from].emplace_back(r, G[r.to].size() - 1);
  }
  int getFlow(int s, int t) {
    int flow = 0;
    while (1) {
      bfs(s);
      if (level[t] < 0) return flow;
      std::fill(iter.begin(), iter.end(), 0);
      for (int f; f = dfs(s, t, Edge::INF), f > 0; flow += f)
        ;
    }
  }

 private:
  void bfs(int s) {
    std::fill(level.begin(), level.end(), -1);
    std::queue<int> Q;
    level[s] = 0;
    for (Q.push(s); !Q.empty(); Q.pop()) {
      auto v = Q.front();
      for (const auto& e : G[v]) {
        if (e.cap <= 0) continue;
        if (level[e.to] >= 0) continue;
        level[e.to] = level[v] + 1;
        Q.push(e.to);
      }
    }
  }
  int dfs(int v, int t, int f) {
    if (v == t) return f;
    for (int& i = iter[v]; i < G[v].size(); i++) {
      auto& e = G[v][i];
      if (e.cap <= 0) continue;
      if (level[v] >= level[e.to]) continue;
      int d = dfs(e.to, t, std::min(f, e.cap));
      if (d <= 0) continue;
      e.cap -= d;
      G[e.to][e.rev].cap += d;
      return d;
    }
    return 0;
  }
};
}
}
//}}}

using namespace std;

int main() {
  int X = in(), Y = in(), E = in();
  orliv::graph::Dinic dinic(X + Y + 2);
  for (int i = 0; i < E; i++) {
    int x = in(), y = in();
    dinic.add(x, X + y);
  }
  for (int x = 0; x < X; x++) dinic.add(X + Y, x);
  for (int y = 0; y < Y; y++) dinic.add(X + y, X + Y + 1);
  cout << dinic.getFlow(X + Y, X + Y + 1) << endl;
  return 0;
}

Measured memory_bytes: 1524