Buggy python submission (verdict: Time Limit Exceeded):
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
input:
3 4 6
0 0
0 2
0 3
1 1
2 1
2 3

output:
3
"""

import sys
from collections import deque


def generate_adj_table(_edges):
    for edge in _edges:
        vx, vy = map(int, edge)
        # vy += x_num
        init_adj_table[vx].append(vy)
        # init_adj_table[vy].append(vx)

    return init_adj_table


def graph_bfs_Hungarian():
    ans = 0
    queue = list()
    prev = [-1] * y_num
    matching = [-1] * y_num

    for v in range(x_num):
        visited = [False] * y_num
        if matching[v] == -1:
            while queue:
                queue.pop()
            queue.append(v)
            prev[v] = -1
            flag = False
            while queue and not flag:
                current = queue[0]
                for adj in adj_table[current]:
                    if not flag:
                        if not visited[adj]:
                            visited[adj] = True
                            queue.append(matching[adj])
                            if matching[adj] >= 0:
                                prev[matching[adj]] = current
                            else:
                                flag = True
                                d, e = current, adj
                                while d != -1:
                                    t = matching[d]
                                    matching[d] = e
                                    # matching[e] = d
                                    d = prev[d]
                                    e = t

                queue.pop()

            if matching[v] != -1:
                ans += 1

    return ans


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    x_num, y_num, e_num = map(int, _input[0].split())
    edges = map(lambda x: x.split(), _input[1:])

    # v_num = x_num + y_num
    init_adj_table = [[] for _ in range(x_num)]
    adj_table = generate_adj_table(edges)
    print(graph_bfs_Hungarian())

Fixed submission:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
input:
3 4 6
0 0
0 2
0 3
1 1
2 1
2 3

output:
3
"""

import sys


def dfs(current, matching, visited):
    for target in range(y_num):
        if (not visited[target]) and (target in adj_table[current]):
            visited[target] = True
            ''' Matching[target] = -1: target not assigned to any of x.
            And dfs(matching[target], matching, visited) = True
            indicates that source in x has been already assigned
            to another target in y. '''
            if matching[target] == -1 or dfs(matching[target], matching, visited):
                matching[target] = current
                return True
    return False


def mbm():
    res = 0
    matching = [-1] * y_num
    for source in range(x_num):
        visited = [False] * y_num
        if dfs(source, matching, visited):
            res += 1
    return res


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    x_num, y_num, e_num = map(int, _input[0].split())
    edges = map(lambda x: x.split(), _input[1:])

    adj_table = tuple(set() for _ in range(x_num))
    for edge in edges:
        vx, vy = map(int, edge)
        adj_table[vx].add(vy)
    print(mbm())