fun main(args: Array<String>) {
    val N = readLine()!!.toInt()
    val A = IntArray(20)
    // 誰が
    val X = Array(20) { IntArray(20) }
    // どうなのか 正直者/不親切な人
    val Y = Array(20) { IntArray(20) }

    for (i in 1..N) {
        A[i] = readLine()!!.toInt()
        for (j in 1..A[i]) {
            val (x, y) = readLine()!!.split(" ").map(String::toInt)
            X[i][j] = x
            Y[i][j] = y
        }
    }

    // 1の数をカウント
    fun counter(value: Int): Int {
        if (value == 0) {
            return 0
        }
        return counter(value.shr(1)) + value.and(1)
    }

    var ans = 0

    // {0, 1, ..., n-1} の部分集合の全探索
    for (bits in 0 until (1.shl(N))) {
        var ok = true
        for (i in 1..N) {
            // 正直者かどうかを判定している
            // 不親切だと仮定している人の証言は無視する
            if (((bits shr (i - 1)) and 1) == 0) {
                continue
            }
            // 証言の数だけ繰り返す

            for (j in 1..A[i]) {
                // 発言と仮定している値に矛盾がないか判定している
                // XORで発言に矛盾がないかを見ている
                // 0,0 → 1
                // 0,1 → 0
                // 1,0 → 0
                // 1,1 → 1
                if ((((bits shr (X[i][j] - 1)) and 1) xor Y[i][j]) == 1) {
                    ok = false
                    break
                }
            }

        }
        if (ok) {
            ans = Math.max(ans, counter(bits))
        }
    }
    println(ans)
}