using System;
using System.Collections.Generic;
using System.Linq;

class Program {
    static void Main(string[] args) {
        int N;
        Input(out N);
        bool?[][] s = new bool?[N][];
        for(int i = 0; i < N; i++) {
            int A;
            Input(out A);
            s[i] = new bool?[N];
            for(int j = 0; j < N; j++) {
                s[i][j] = null;
            }
            for(int j = 0; j < A; j++) {
                int x;
                int y;
                Input(out x, out y);
                s[i][x - 1] = y == 1 ? true : false;
            }
        }
        int max = 0;
        bool[][] flags = GetAllBitFlags(N);
        //2^N通りを全て探索
        for(int i = 0; i < (1 << N); i++) {
            bool isOk = true;
            int count = 0;
            //全ての人を探索
            for(int j = 0; j < N; j++) {
                //i番目の状況でj番目の人が正直者だと仮定されるならば
                if(flags[i][j]) {
                    //j番目の人の証言を全て探索
                    for(int k = 0; k < s[j].Length; k++) {
                        //j番目の人のk番目の人への証言があるならば
                        if(s[j][k] != null) {
                            //その証言が正直者ならば
                            if((bool)s[j][k]) {
                                if(flags[i][k] == false) {
                                    isOk = false;
                                }
                            } else {
                                if(flags[i][k] == true) {
                                    isOk = false;
                                }
                            }
                        }
                    }
                    count++;
                }
            }
            if(!isOk) {
                count = 0;
            }
            if(max < count) {
                max = count;
            }
        }
        Console.WriteLine(max);
    }
    static bool[][] GetAllBitFlags(int N) {
        bool[][] ret = new bool[1 << N][];
        for(int i = 0; i < (1 << N); i++) {
            ret[i] = new bool[N];
            for(int j = 0; j < N; j++) {
                if((1 & (i >> j)) == 1) {
                    ret[i][j] = true;
                }
            }
        }
        return ret;
    }
    static int[] GetSequence(int first, Func<int, int> recurrence, int n) {
        int[] ret = new int[n];
        ret[0] = first;
        for(int i = 1; i < n; i++) {
            ret[i] = recurrence.Invoke(ret[i - 1]);
        }
        return ret;
    }
    static T ChangeT<T>(string s) => (T)Convert.ChangeType(s, typeof(T));
    static void Input<A>(out A a) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
    }
    static void Input<A, B>(out A a, out B b) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
    }
    static void Input<A, B, C>(out A a, out B b, out C c) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
    }
    static void Input<A, B, C, D>(out A a, out B b, out C c, out D d) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
    }
    static void Input<A, B, C, D, E>(out A a, out B b, out C c, out D d, out E e) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
        e = ChangeT<E>(words[4]);
    }
    static void Input<A, B, C, D, E, F>(out A a, out B b, out C c, out D d, out E e, out F f) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
        e = ChangeT<E>(words[4]);
        f = ChangeT<F>(words[5]);
    }
    static void InputArray<T>(out T[] array) {
        array = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries).Select(s => ChangeT<T>(s)).ToArray();
    }
}

Measured memory_bytes: 13408