CodeEff/ECCO huggingface dataset:
# Original solution
def counter(x):
    if x == 0:
        return 0
    return counter(x >> 1) + (x & 1)


N = int(eval(input()))
A = [0 for i in range(20)]
x = [[0 for i in range(20)] for j in range(20)]
y = [[0 for i in range(20)] for j in range(20)]

for i in range(1, N + 1):
    A[i] = int(eval(input()))
    for j in range(1, A[i] + 1):
        x[i][j], y[i][j] = list(map(int, input().split()))

# 2^N 通りをbit全探索
# kが正直者 = 2進数表記のk-1桁目が1 (1 <= k <= N)
ans = 0
for bits in range(1, 1 << N):
    ok = True
    for i in range(1, N + 1):
        # 不親切な人の意見は無視
        if not ((bits >> (i - 1)) & 1):
            continue
        for j in range(1, A[i] + 1):
            # x_ij が正直者であることが偽であれば False
            if ((bits >> (x[i][j] - 1)) & 1) ^ y[i][j]:
                ok = False
    if ok:
        ans = max(ans, counter(bits))

print(ans)


# Optimized solution
def counter(x):
    if x == 0:
        return 0
    return counter(x >> 1) + (x & 1)


N = int(eval(input()))
A = [0 for i in range(20)]
x = [[0 for i in range(20)] for j in range(20)]
y = [[0 for i in range(20)] for j in range(20)]

for i in range(1, N + 1):
    A[i] = int(eval(input()))
    for j in range(1, A[i] + 1):
        x[i][j], y[i][j] = list(map(int, input().split()))

# 2^N 通りをbit全探索
# kが正直者 = 2進数表記のk-1桁目が1 (1 <= k <= N)
ans = 0
for bits in range(1, 1 << N):
    ok = True
    for i in range(1, N + 1):
        # 不親切な人の証言は無視
        if ((bits >> (i - 1)) & 1) == 0:
            continue
        for j in range(1, A[i] + 1):
            # x_ij が正直者であることが偽であれば False
            if ((bits >> (x[i][j] - 1)) & 1) != y[i][j]:
                ok = False
    if ok:
        ans = max(ans, counter(bits))

print(ans)
# Original solution
n=int(eval(input()))
a=[]
l=[0]*n
ans=0
for i in range(n):
	a.append(int(eval(input())))
	l[i]=[list(map(int,input().split())) for i in range(a[-1])]
#print(a,l)
for i in range(2**n):
	i=format(i,'b').zfill(n)
	c=[]
	for j in range(n):
		if i[j]=='1':
			c.append(j)
	#print(c,l)
	for j in c:
		for k in l[j]:
			#print(k)
			if k[1]==1 and (k[0]-1 not in c):
				break
			elif k[1]==0 and (k[0]-1 in c):
				break
		else:
			continue
		break
	else:
		#print(ans)
		ans=max(ans,len(c))
print(ans)




# Optimized solution
n=int(eval(input()))
a=[]
l=[0]*n
ans=0
for i in range(n):
	a.append(int(eval(input())))
	l[i]=[list(map(int,input().split())) for i in range(a[-1])]
for i in range(2**n):
	i=format(i,'b').zfill(n)
	c=[]
	for j in range(n):
		if i[j]=='1':
			c.append(j)
	for j in c:
		for k in l[j]:
			#print(k)
			if k[1]==1 and (k[0]-1 not in c):
				break
			elif k[1]==0 and (k[0]-1 in c):
				break
		else:
			continue
		break
	else:
		ans=max(ans,len(c))
print(ans)
# Original solution
#
# abc147 c
#
import sys
from io import StringIO
import unittest


class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)

    def test_入力例_1(self):
        input = """3
1
2 1
1
1 1
1
2 0"""
        output = """2"""
        self.assertIO(input, output)

    def test_入力例_2(self):
        input = """3
2
2 1
3 0
2
3 1
1 0
2
1 1
2 0"""
        output = """0"""
        self.assertIO(input, output)

    def test_入力例_3(self):
        input = """2
1
2 0
1
1 0"""
        output = """1"""
        self.assertIO(input, output)


def resolve():
    N = int(eval(input()))
    C = []
    for i in range(N):
        a = int(eval(input()))
        C.append([list(map(int, input().split())) for j in range(a)])

    ans = 0
    for bit in range(1 << N):
        t = 0
        for i in range(N):
            if bit & (1 << i):
                for c in C[i]:
                    if bit & (1 << c[0]-1) != (1 << c[0]-1)*c[1]:
                        break
                else:
                    t += 1
        if t == bin(bit).count("1"):
            ans = max(ans, t)
    print(ans)


if __name__ == "__main__":
     # unittest.main()
     resolve()


# Optimized solution
#
# abc147 c
#
import sys
from io import StringIO
import unittest


class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)

    def test_入力例_1(self):
        input = """3
1
2 1
1
1 1
1
2 0"""
        output = """2"""
        self.assertIO(input, output)

    def test_入力例_2(self):
        input = """3
2
2 1
3 0
2
3 1
1 0
2
1 1
2 0"""
        output = """0"""
        self.assertIO(input, output)

    def test_入力例_3(self):
        input = """2
1
2 0
1
1 0"""
        output = """1"""
        self.assertIO(input, output)


def resolve():
    N = int(eval(input()))
    C = []
    for i in range(N):
        a = int(eval(input()))
        C.append([list(map(int, input().split())) for j in range(a)])

    ans = 0
    for bit in range(1 << N):
        f = True
        for i in range(N):
            if bit & (1 << i):
                for c in C[i]:
                    if bit & (1 << c[0]-1) != (1 << c[0]-1)*c[1]:
                        f = False
                        break
        if f == True:
            ans = max(ans, bin(bit).count("1"))
    print(ans)


if __name__ == "__main__":
    # unittest.main()
    resolve()
# Original solution
N=int(eval(input()))
A=[0]*N
shougen=[[] for i in range(0,N)]
for i in range(0,N):
    A[i]=int(eval(input()))
    for j in range(0,A[i]):
        a,b=list(map(int,input().split()))
        shougen[i].append([a,b])
m=0
for i in range(0,2**N):
    flag=0
    check=[]
    for j in range(0,N):
        if i>>j & 1==1:
            check.extend(shougen[j])
    for j in range(0,N):
        if ([j+1,0] in check) or ([j+1,1] in check):
            if [j+1,0] in check:
                if j==0:
                    data=[0]
                else:
                    data.append(0)
            if [j+1,1] in check:
                if j==0:
                    data=[1]
                else:
                    data.append(1)

        else:
            if j==0:
                data=[2]
            else:
                data.append(2)
    for j in range(0,N):
        if data[j]!=2:
            if int(data[j])!=(i>>j)%2 :
                flag=1
    if len(data)!=N:
        flag=1
    if flag==0:
        test=sum(i>>j &1 for j in range(0,N))
        if test>m:
            m=test

print(m)


# Optimized solution
N=int(eval(input()))
shougen=[(0,0) for i in range(0,N)]
for i in range(0,N):
    A=int(eval(input()))
    honest=0
    unkind=0
    for j in range(0,A):
        x,y=list(map(int,input().split()))
        if y==0:
            unkind+=2**(x-1)
        else:
            honest+=2**(x-1)
    shougen[i]=(honest,unkind)

ans=0
for i in range(0,2**N):
    honest=i
    unkind=2**N-1-i
    check=True
    test=0
    for j in range(0,N):
        if (i>>j)&1 ==1:
            test+=1
            x,y=shougen[j]
            if (honest-x)^x!=honest or (unkind-y)^y!=unkind:
                check=False
    if check:
        if test>ans:
            ans=test

print(ans)
# Original solution
import sys


def kensho(x,tlist):
    for lis in tlist:
        if((x>>(lis[1]-1)) & 1 == lis[2]):
            pass
        else:
            return -1

    return bin(x).count('1')


def main():
    N = int(eval(input()))
    xy=[]
    ans=0

    for i in range(1,N+1):
        An= int(eval(input()))
        for j in range(0,An):
            x, y = list(map(int, input().split()))
            xy.append([i,x,y])

    cnt = N

    tlist=[]
    for x in range (2 ** cnt):
        for y in range(cnt):
            if((x>>y) & 1):
                for z in xy:
                    if(z[0]==y+1):
                        tlist.append(z)

        anstack = kensho(x,tlist)
        if(ans<anstack):
            ans=anstack

        tlist.clear()

    print(ans)

main()

# Optimized solution
import sys

def kensho(x,tlist):
    for lis in tlist:
        if((x>>(lis[1]-1)) & 1 == lis[2]):
            pass
        else:
            return -1

    return bin(x).count('1')


def main():
    N = int(eval(input()))
    xy=[]
    ans=0

    for i in range(1,N+1):
        An= int(eval(input()))
        for j in range(0,An):
            x, y = list(map(int, input().split()))
            xy.append([i,x,y])

    cnt = N

    tlist=[]
    for x in range (2 ** cnt):
        for y in range(cnt):
            if((x>>y) & 1):
                for z in xy:
                    if(z[0]==y+1):
                        tlist.append(z)

        anstack = kensho(x,tlist)
        if(ans<anstack):
            ans=anstack

        del tlist[:]

    print(ans)

main()
# Original solution
N = int(eval(input()))
A = [None]*N
x = [[None]*N for _ in range(N)]
y = [[None]*N for _ in range(N)]

for i in range(N):
    A[i] = int(eval(input()))
    for j in range(A[i]):
        x[i][j],y[i][j] = list(map(int, input().split()))
        

ans =0
for num in range(2**N):
    #bit = bin(num)#正直者リスト
    flag = 1 #これが1のままならOK
    
    #N人を順に見る
    for i in range(N):
        #下からi桁目を取り出す
        if (num>>i & 1)==1:#正直者なら検討
            
            #各発言に対して，NGケースを調査
            for j in range(N):
                #xijの対応に注意，文章では1から
                if x[i][j] != None and y[i][j]!=(num>>(x[i][j]-1) & 1):
                    flag = 0
        if flag ==0:
            break
    if flag ==1:
        ans = max(ans,bin(num).count("1"))
print(ans)

# Optimized solution
N = int(eval(input()))
A = [None]*N
x = [[None]*N for _ in range(N)]
y = [[None]*N for _ in range(N)]

for i in range(N):
    A[i] = int(eval(input()))
    for j in range(A[i]):
        x[i][j],y[i][j] = list(map(int, input().split()))
        

ans =0
for num in range(2**N):
    #bit = bin(num)#正直者リスト
    flag = 1 #これが1のままならOK
    
    #N人を順に見る
    for i in range(N):
        #下からi桁目を取り出す
        if (num>>i & 1)==1:#正直者なら検討
            
            #各発言に対して，NGケースを調査
            for j in range(N):
                #xijの対応に注意，文章では1から
                if x[i][j] != None and y[i][j]!=(num>>(x[i][j]-1) & 1):
                    flag = 0
                elif x[i][j] == None:
                    break
        if flag ==0:
            break
    if flag ==1:
        ans = max(ans,bin(num).count("1"))
print(ans)
# Original solution
'''
N人の「正直者」、「不親切な人」のすべての組み合わせを生成し、
正直者の証言が組み合わせに矛盾していないか確認する. 
矛盾していない組み合わせの正直者の最大数が解答.
組み合わせは bit で表現している. Nビット用意し、
1が立っていると正直者、0だと不親切な人. 
この組み合わせ状況と正直者の証言が矛盾しないか確認する.
'''
N = int(eval(input()))

evidences = [[] for _ in range(N)]
for i in range(N):
    A = int(eval(input()))
    for _ in range(A):
        x, y = list(map(int, input().split()))
        evidences[i].append((x - 1, y))

result = 0
for i in range(1, 2 ** N):
    consistent = True
    for j in range(N):
        if (i >> j) & 1 == 0:
            continue
        for x, y in evidences[j]:
            if (i >> x) & 1 != y:
                consistent = False
                break
        if not consistent:
            break
    if consistent:
        result = max(result, bin(i)[2:].count('1'))
print(result)

# Optimized solution
import itertools 
N = int(eval(input()))
evidence_dit = {} 
for i in range(N):
    A = int(eval(input()))
    x_y = []
    if A == 0:
        evidence_dit[i] = []
    for j in range(A):
        x_y.append(list(map(int,input().split())))        
        evidence_dit[i] = x_y 
ans = 0
attribute = [0,1] 
for i in itertools.product(attribute,repeat=N):
    flag = False    
    for j in range(N):
       if i[j] == 1:            
            for k in evidence_dit[j]:
                if i[k[0]-1] != k[1]:
                    flag = True
                    break
            if flag:
                break 
    if flag == False:
        ans = max(ans,sum(i))        
print(ans)
'''
入力:辞書型で置いておくことにした。
{0: [[2, 1], [3, 0]], 1: [[3, 1], [1, 0]], 2: [[1, 1], [2, 0]]}
証言が無い場合に [ ] を入れる。
attribute = [0,1] 
for i in itertools.product(attribute,repeat=N):
正直、不正直のパターンを列挙するところ、itertoolsで0,1の重複順列
for i in range(2 ** N):
    h = [0] * N 
    for j in range(N):
        if (i >> j) & 1:
            h[j] = 1
ビット演算子
i >> j　i を右に j ビットシフト
5 >> 2　5 を右に 2 ビットシフト
　　　　 101｜　➡　001｜01　➡　001
　　　　 右へ２つずらして足りなくなった桁は0にする。　
5 & 1　➡　101 AND 001　➡　001
　　　　　　両方１のところだけ１になる。
if 5 & 1:　5 & 1 の答えが１なら True、他は False
[0, 0, 0] [1, 0, 0] [0, 1, 0] [1, 1, 0] [0, 0, 1] [1, 0, 1] 
[0, 1, 1] [1, 1, 1]、のような0,1の全パターンを出している。
'''
# Original solution
n=int(eval(input()))
a=[0]*n
x=[[0]*n for i in range(n)]
y=[[0]*n for i in range(n)]

for i in range(n):
  a[i]=int(eval(input()))
  for j in range(a[i]):
    x[i][j],y[i][j]=list(map(int,input().split()))
    x[i][j]-=1
    
def check(honest):
  for i in range(n):
    if not honest[i]:
      continue
    for j in range(a[i]):
      if y[i][j]==1 and not honest[x[i][j]]:
        return False
      if y[i][j]==0 and honest[x[i][j]]:
        return False
  return True

def dfs(honest):
  if len(honest)==n:
    if check(honest):
      return sum(honest)
    else:
      return 0
  return max(dfs(honest + [1]),
             dfs(honest + [0]))
 
print((dfs([])))

# Optimized solution
n=int(eval(input()))
a=[0]*n
x=[[0]*n for i in range(n)]
y=[[0]*n for i in range(n)]

for i in range(n):
  a[i]=int(eval(input()))
  for j in range(a[i]):
    x[i][j],y[i][j]=list(map(int,input().split()))
    x[i][j]-=1
    
def check(honest):
  for i in range(n):
    if not honest[i]:
      continue
    for j in range(a[i]):
      if y[i][j]==1 and not honest[x[i][j]]:
        return 0
      if y[i][j]==0 and honest[x[i][j]]:
        return 0
  return 1

def dfs(honest):
  if len(honest)==n:
    if check(honest):
      return sum(honest)
    else:
      return 0
  return max(dfs(honest + [1]),
             dfs(honest + [0]))
 
print((dfs([])))
# Original solution
def II(): return int(eval(input()))
def MI(): return list(map(int, input().split()))
N=II()
shogens=[]
for i in range(N):
  a=II()
  shogens.append([])
  for j in range(a):
    x,y=MI()
    x-=1
    shogens[-1].append((x,y))
def is_honest(i,j):
  return (i>>j)%2==1
def honest_cnt(i):
  ans=0
  for j in range(N):
    ans+=is_honest(i,j)
  return ans
ans=0
for i in range(1<<N):
  ok=True
  for j in range(N):
    if not is_honest(i,j):
      continue
    for (x,y) in shogens[j]:
      if y==0 and is_honest(i,x):
        ok=False
      if y==1 and not is_honest(i,x):
        ok=False  
  if ok:
    ans=max(ans,honest_cnt(i))
print(ans)

# Optimized solution
def II(): return int(eval(input()))
def MI(): return list(map(int, input().split()))
N=II()
a=[0]*N
x=[[0]*N for i in range(N)]
y=[[0]*N for i in range(N)]
for i in range(N):
  a[i]=II()
  for j in range(a[i]):
    x[i][j],y[i][j]=MI()
    x[i][j]-=1
def check(honest):
  for i in range(N):
    if not honest[i]:
      continue
    for j in range(a[i]):
      if y[i][j]==0 and honest[x[i][j]]:
        return False
      if y[i][j]==1 and not honest[x[i][j]]:
        return False
  return True
def dfs(honest):
  if len(honest)==N:
    if check(honest):
      return sum(honest)
    else:
      return 0
  return max(dfs(honest+[True]),dfs(honest+[False]))
print((dfs([])))
# Original solution
g = [[-1 for _ in range(15)] for _ in range(15)]
n = int(eval(input()))
ans=0
for i in range(n):
  m = int(eval(input()))
  for j in range(m):
    x,y = list(map(int, input().split()))
    g[i][x-1] = y
for i in range(1<<n):
  honests = [0 for _ in range(n)]
  for j in range(n):
    if (i>>j) &1:
      honests[j] = 1     
  ok = True  
  for j in range(n):
    if honests[j]:
      for k in range(n):
        if g[j][k] == -1: continue
        if g[j][k] != honests[k]: ok = False
  if ok:
    ans = max(ans, honests.count(1))
print(ans)

# Optimized solution
g = [[-1 for _ in range(15)] for _ in range(15)]
n = int(eval(input()))
ans=0
for i in range(n):
  m = int(eval(input()))
  for j in range(m):
    x,y = list(map(int, input().split()))
    g[i][x-1] = y
for i in range(1<<n):
  honests = [0 for _ in range(n)]
  for j in range(n):
    if (i>>j) &1:
      honests[j] = 1     
  ok = True  
  for j in range(n):
    if honests[j]:
      for k in range(n):
        if g[j][k] == -1: continue
        if g[j][k] != honests[k]: ok = False
  if ok:
    ans = max(ans, honests.count(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の値を出力する。
'''
# Original solution
def popcnt(n):
    return bin(n).count("1")

n = int(eval(input()))
grid = []

for i in range(n):
    p = int(eval(input()))
    for j in range(p):
        array = [i] +list(map(int, input().strip().split(' ')))
        array[1] = array[1] - 1
        grid.append(array)


truth = 0
count = 0

for i in range(2**n):
    k = (bin(i)[2:]).zfill(n)
    count = 0
    for j in range(len(grid)):
        if int(k[grid[j][0]]) == 1:
            if (int(k[grid[j][1]]) == 1 and grid[j][2] == 0) or (int(k[grid[j][1]]) == 0 and grid[j][2] == 1):
                count = 1
    if count == 0:
        if truth < popcnt(i):
            truth = popcnt(i)

print(truth)


# Optimized solution
def popcnt(n):
    return bin(n).count("1")

n = int(eval(input()))
grid = []

for i in range(n):
    p = int(eval(input()))
    for j in range(p):
        array = [i] +list(map(int, input().strip().split(' ')))
        array[1] = array[1] - 1
        grid.append(array)


truth = 0
count = 0

for i in range(2**n):
    k = (bin(i)[2:]).zfill(n)
    count = 0
    for j in range(len(grid)):
        if int(k[grid[j][0]]) == 1:
            if (int(k[grid[j][1]]) == 1 and grid[j][2] == 0) or (int(k[grid[j][1]]) == 0 and grid[j][2] == 1):
                count = 1
                break
    if count == 0:
        if truth < popcnt(i):
            truth = popcnt(i)

print(truth)
# Original solution
def main():
    n = int(eval(input()))
    ttn = [[-1] * n for _ in range(n)]  # Testimonies.
    for i in range(n):
        a = int(eval(input()))
        for j in range(a):
            x, y = [int(z) for z in input().split()]
            x -= 1
            ttn[i][x] = y  # i says that x is honest guy or not.
    ans = set()
    # for else で頑張ったが，フラグを作ったほうがずっと分かりやすいだろう。
    for i in range(2 ** n):
        tmp = [i >> j & 1 for j in range(n)]  # Bit-shift.
        for k, tm in enumerate(tmp):
            if tm:
                for l, tt in enumerate(ttn[k]):
                    if tt == -1:
                        continue
                    if tt != tmp[l]:
                        break
                else:
                    continue
                break
        else:
            ans.add(bin(i).count('1'))
    return max(ans)


if __name__ == '__main__':
    print((main()))


# Optimized solution
def main():
    n = int(eval(input()))
    ttn = [[-1] * n for _ in range(n)]  # Testimonies.
    for i in range(n):
        a = int(eval(input()))
        for j in range(a):
            x, y = [int(z) for z in input().split()]
            x -= 1
            ttn[i][x] = y  # i says that x is honest guy or not.
    ans = set()
    for i in range(2 ** n):
        tmp = [i >> j & 1 for j in range(n)]  # Bit-shift.
        possible = True
        for k, tm in enumerate(tmp):
            if not possible:
                break
            if tm:
                for l, tt in enumerate(ttn[k]):
                    if tt == -1:
                        continue
                    if tt != tmp[l]:
                        possible = False
                        break
        if possible:
            ans.add(bin(i).count('1'))
    return max(ans)


if __name__ == '__main__':
    print((main()))
# Original solution
n = int(eval(input()))
tst = [[] for i in range(n)]
for i in range(n):
  a = int(eval(input()))
  for j in range(a):
    x,y = list(map(int,input().split()))
    tst[i].append([x,y])
ans = 0
for bit in range(1<<n):
  liars = [0]*n
  check = 1
  for i in range(n):
    if (bit>>i)&1:
      liars[-1-i] = 1
  for i in range(n):
    if liars[i]:
      for l in tst[i]:
        if l[1]!=liars[l[0]-1]:
          check = 0
          break
  temp = 0
  if check:
    temp = sum(liars)
  ans = max(ans,temp)
print(ans)

# Optimized solution
n = int(eval(input()))
tst = [[] for i in range(n)]
for i in range(n):
    a = int(eval(input()))
    for j in range(a):
        x,y = list(map(int,input().split()))
        tst[i].append([x,y])
ans = 0
for bit in range(1<<n):
    liars = [0]*n
    check = 1
    for i in range(n):
        if (bit>>i)&1:
            liars[-1-i] = 1
    for i in range(n):
        if not liars[i]:
            continue
        for l in tst[i]:
            if l[1]!=liars[l[0]-1]:
                check = 0
                break
    if check:
        ans = max(ans,sum(liars))
print(ans)
# Original solution
# import numpy as np
# import scipy as sp

n = int(eval(input()))
info = []
for i in range(n):
    a = int(eval(input()))
    for _ in range(a):
        x, y = list(map(int, input().split()))
        info.append([i, x-1, y])

ans = 0
for i in range(2 ** n):
    bit = [0] * n
    for j in range(n):
        if ((i >> j) & 1):
            bit[j] = 1

    flag = True
    # print(bit)
    for idx, j in enumerate(bit):
        if j == 1:
            for k in [x for x in info if x[0] == idx]:
                # print(' ', k)
                if bit[k[1]] != k[2]:
                    flag = False
    if flag:
        ans = max(ans, sum(bit))
    # print(ans)
print(ans)


# Optimized solution
# import numpy as np
# import scipy as sp

n = int(eval(input()))
info = []
for i in range(n):
    a = int(eval(input()))
    for _ in range(a):
        x, y = list(map(int, input().split()))
        info.append([i, x-1, y])

ans = 0
for i in range(2 ** n):
    bit = [0] * n
    for j in range(n):
        if ((i >> j) & 1):
            bit[j] = 1

    flag = True
    # print(bit)
    for idx, j in enumerate(bit):
        if not flag:
            break
        if j == 1:
            for k in [x for x in info if x[0] == idx]:
                # print(' ', k)
                if bit[k[1]] != k[2]:
                    flag = False
    if flag:
        ans = max(ans, sum(bit))
    # print(ans)
print(ans)