def parse_input():
    N, M = map(int, input().split())
    assert 1 <= N <= 1000
    assert 1 <= M <= 100

    flags = []
    for _ in range(N):
        ki = int(input())
        colori = set([int(cj) for cj in input().split()])
        assert ki == len(colori)
        flags.append(colori)

    return N, M, flags


def input_to_bigraph(N, M, flags):
    V = N + M
    bigraph = [[] for _ in range(V)]
    for country, flag in enumerate(flags):
        for color in flag:
            bigraph[N + color - 1].append(country)
            bigraph[country].append(N + color - 1)
    return bigraph


def augment(bigraph, matching, visited, current_node):
    for v in bigraph[current_node]:
        if not visited[v]:
            visited[v] = True
            if matching[v] is None or augment(
                bigraph, matching, visited, current_node=matching[v]
            ):
                matching[v] = current_node  # Augmenting path was found
                return True
    return False  # Augmenting path not found


def size_minimum_cover_bipartite(bigraph):
    # We look for a maximal matching an use Konig theorem
    V = len(bigraph)
    matching = [None for _ in bigraph]

    for u in range(V):
        augment(bigraph, matching, visited=[False] * V, current_node=u)

    return sum(v is not None for v in matching) // 2  # Size of the matching


N, M, flags = parse_input()
bigraph = input_to_bigraph(N, M, flags)
print(size_minimum_cover_bipartite(bigraph))
