# Original solution
g = [[-1 for _ in range(15)] for _ in range(15)]#証言格納用
n = int(eval(input()))#証言なし-1で初期化
ans=0
for i in range(n):#n人の人について、一人一人、入力
  m = int(eval(input()))#証言の個数をもらう
  for j in range(m):#m個の証言を入力
    x,y = list(map(int, input().split()))
    g[i][x-1] = y#i番目の人の証言を格納、人の番号xは0始まり
    
for i in range(1<<n):#Bit全探索開始
  honests = [0 for _ in range(n)]#正直者フラグ、後で1で人数計算
  for j in range(n):#n人を一人ずつ、チェックする
    if (i>>j) &1:#Bitが立っているかを1で表す
      honests[j] = 1#Bitが立っていれば、j番目は正直と仮定 
      
  ok = True#矛盾が無い仮定で、証言を検証する
  for j in range(n):#n人を一人ずつ、チェック(j番目の人を見る)
    if honests[j]:#j番目が、もし正直なら証言を検証(不正直の証言は無視)
      for k in range(n):#j番目の人の、k番目の人に対する証言を検証
        if g[j][k] == -1: continue#証言していなければ、飛ばす
        if g[j][k] != honests[k]: ok = False#証言とフラグ仮定が不一致
          
  if ok:#矛盾がないケースについて調べる
    ans = max(ans, honests.count(1))#正直であるフラグ1が立っている数
print(ans)
'''
・正直者の人の組を全ての組合せで仮定する。
・正直者と仮定した人の証言が仮定に矛盾するとき、
その正直者の選び方の組はあり得ない。
・正直者と仮定した人の証言同士の矛盾は調べる必要はない。
ある人に対して矛盾する二つの証言があるとき、
どちらか一方の証言は必ず仮定に矛盾する。したがって、
この仮定があり得ないことを調べるには仮定と証言の矛盾を調べるだけでよい。
・全ての証言が矛盾しない正直者の選び方の組のうち、
正直者が最も多い組の正直者の人数を求めれば良い。
人xの人yに対する証言のデータを二次元配列gへ次のような対応関係で
格納しておく。なお、ここでは人の番号は配列のオフセットに合わせるため
0から始めるものとする。
・人xが人yに対して正直者であると証言するとき、
二次元配列g[x][y]を1にする。
・人xが人yに対して不親切な人であると証言するとき
二次元配列g[x][y]を0とする。
・人xが人yに対して言及していないとき、
二次元配列g[x][y]を-1にする。
・入力よりNの最大が15なので、
15行15列の二次元配列gをデフォルト値-1用意しておく
・全員の人数を表す値を受け取る。
・用意した配列に人iが人jに対して述べる証言のデータを格納していく。
・人iの証言の数mを受け取る。
・人iの証言を受け取るためm回次のループを回す。
・証言を表す二つの値を受け取り二次元配列gに格納する。
人iが「人xはyである」と証言しているときg[i][x]=yである。
（入力で受け取る「人の番号」は1から始まるため、
コードでは受け取った値から1引いている。）
g = [[-1 for _ in range(15)] for _ in range(15)]
n = int(input())
for i in range(n):
 m = int(input())
 for j in range(m):
   x,y = map(int, input().split())
   g[i][x-1] = y
二次元配列gの作成と入力の受け取りは以上である。
次に問題を解く中心となるコードを実装していく。
まず、全ての正直者の組を表現するために二進数表記を用いることを考える。
二進数の右端の桁を0桁目とする。またkを0から14までの整数とする。
・「k桁目が1である」を「人kは正直者である」
・「k桁目が0である」を「人kは不親切な人である」
作り出した正直者の組それぞれに対して何らかの処理を行うため、
これは全bit探索である。
「正直者の組を作りだす」部分のコード。
・カウンタ変数iを1から2^15まで変化させ、次の処理を繰り返す。
・正直者の番号を格納する要素数nの配列honestsをデフォルト値0で作る。
・iを二進数で表現したときj桁目が1であればhonests[j]に1を追加する。
for i in range(1<<n):
 honests = [0 for _ in range(n)]
 for j in range(n):
   if (i>>j) &1:
     honests[j] = 1 
honests[j]が1であることは,人jは正直者であると仮定することに対応する。
次はhonestsの仮定と証言gに矛盾がないか調べ、求める値「N人のうち
正直者であり得る最大人数」を出力するまでの実装をおこなう。
仮定と証言に矛盾があればそのhonestsで表現された組はあり得ない。
・求める値「N人のうち正直者であり得る最大人数」を格納するための
変数ansをデフォルト値0で用意しておく。
求める値は0以上の値であり以下のループ処理によって、
より大きな値で更新され得る。最終的に最大値が格納される。
・ある正直者の組に矛盾がなかったことを表す変数okをデフォルト値
Trueで用意しておく
・外側のループで配列honestsを作る。作ったhonestsの要素を順に調べる。
honests[j]が1ならば証言g[j]は正しいのでg [j]を以下のように調べる。
・g[j][k]が-1ならば何もしなくてよいので次の証言を調べるループへ移る。
・g[i][k]がhonests[k]の値と異なるならばこの正直者の組はあり得ないので
変数okをFalseにする。
・okがTureのときhonestsの要素の値が1であるものの数（つまり正直者の数）を
数えてansより大きいならばその値をansに代入する。
・最終的なansの値を出力する。
'''

# Optimized solution
def II(): return int(eval(input()))
def MI(): return list(map(int, input().split()))
def LI(): return list(map(int, input().split()))

N=II()
ans=0
List=[[-1 for _ in range(N)] for _ in range(N)]
for j in range(N):
  A=II()
  for i in range(A):
    x,y=MI()
    x-=1
    List[j][x]=y
for i in range(1<<N):
  honests=[0]*N
  for j in range(N):
    if 1&(i>>j):
      honests[j]=1
  ok=True
  for j in range(N):
    if honests[j]:
      for k in range(N):
        if List[j][k]==-1:
          continue
        if List[j][k]!=honests[k]:
          ok=False
  if ok:
    ans=max(ans,honests.count(1))
print(ans)