#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
#include<math.h>
#include<iomanip>
#include<set>
#include<limits.h>
#include<cmath>
#include<queue>
#include<stack>

#include<stdio.h>
#include<stdlib.h>

#define rep(i,n) for(ll i = 0; i < (ll)n; i++)
#define swap(a,b) a^=b;b^=a;a^=b;
#define chmax(a,b) {if(a < b) a = b;}
#define chmin(a,b) {if(a > b) a = b;}

using namespace std;
typedef long long ll;
ll gcd(ll, ll);
vector<bool> to_binary(int);
ll nCr(ll n, ll r);

const ll INF = 1LL << 60;

typedef tuple<ll, ll> mtupl;

bool mycomp(mtupl x, mtupl y) {
	return get<1>(x) < get<1>(y);
}

int vsum(vector<int> v) {
	int res = 0;
	for (auto it = v.begin(); it != v.end(); it++)
		res += *it;
	return res;
}

int vmin(vector<int> v) {
	int min = INT32_MAX;
	for (auto it = v.begin(); it != v.end(); it++)
		min = std::min(min, *it);
	return min;
}

int vmax(vector<int> v) {
	int max = INT32_MIN;
	for (auto it = v.begin(); it != v.end(); it++)
		max = std::max(max, *it);
	return max;
}

ll gcd(ll A, ll B) {
	if (A == 0 || B == 0) return max(A, B);
	int r = A % B;
	while (r != 0) {
		A = B;
		B = r;
		r = A % B;
	}
	return B;
}

vector<ll> prime_factor(int64_t n) {
	//map< ll, ll > ret;
	vector<ll> ret;
	for (ll i = 2; i * i <= n; i++) {
		while (n % i == 0) {
			//ret[i]++;
			ret.push_back(i);
			n /= i;
		}
	}
	if (n != 1)ret.push_back(n);// ret[n] = 1;
	return ret;
}

const int MAX = 1000000;
const int MOD = 1000000007;
ll fac[MAX], finv[MAX], inv[MAX];

void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
		finv[i] = finv[i - 1] * inv[i] % MOD;
	}
}
ll COM(int n, int k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

struct edge {
	ll to;
	ll cost;
};

void Solve(int N, ll* depth) {
	//printf("N = %d\n", N);

	ll Counter[6] = { 0 };

	for (Counter[0] = 0; Counter[0] <= min(N / 100000,9); Counter[0]++) {
		for (Counter[1] = 0; Counter[1] <= min(N / 10000,9); Counter[1]++) {
			for (Counter[2] = 0; Counter[2] <= min(N / 1000,9); Counter[2]++) {
				for (Counter[3] = 0; Counter[3] <= min(N / 100,9); Counter[3]++) {
					for (Counter[4] = 0; Counter[4] <= min(N / 10,9); Counter[4]++) {
						for (Counter[5] = 0; Counter[5] <= min(N / 1,9); Counter[5]++) {
							ll calc = 0;
							for (int i = 0; i < 6; i++) {
								calc += Counter[i] * (int)pow(10, 6 - i - 1);
							}
							//printf("%lld\n", calc);
							ll next = calc;
							for (int i = 0; i < 6; i++) {
								next += Counter[i];
							}

							//printf("%lld %lld\n", calc, next);

							if (next == N) {
								(*depth)++;
								Solve(calc, depth);
							}
						}
					}
				}
			}
		}
	}

	/*
	int Keisuu6 = N / 100001;
	if (10 <= Keisuu6) return;
	for (int a = 0; a <= Keisuu6; a++) {
		int tmp5 = N - a * 100001;
		int Keisuu5 = tmp5 / 10001;
		if (10 <= Keisuu5) continue;
		for (int b = 0; b <= Keisuu5; b++) {
			int tmp4 = tmp5 - b * 10001;
			int Keisuu4 = tmp4 / 1001;
			if (10 <= Keisuu4) continue;
			for (int c = 0; c <= Keisuu4; c++) {
				int tmp3 = tmp4 - c * 1001;
				int Keisuu3 = tmp3 / 101;
				if (10 <= Keisuu3) continue;
				for (int d = 0; d <= Keisuu3; d++) {
					int tmp2 = tmp3 - d * 101;
					int Keisuu2 = tmp2 / 11;
					if (10 <= Keisuu2) continue;
					for (int e = 0; e <= Keisuu2; e++) {
						int tmp1 = tmp2 - e * 11;
						int Keisuu1 = tmp1 / 2;
						if (10 <= Keisuu1) continue;
						int calc = Keisuu1 + Keisuu2 * 10 + Keisuu3 * 100 + Keisuu4 * 1000 + Keisuu5 * 10000 + Keisuu6 * 100000;
						int next = calc + Keisuu1 + Keisuu2 + Keisuu3 + Keisuu4 + Keisuu5 + Keisuu6;
						if (next == N) {
							(*depth)++;
							Solve(calc, depth);
						}
						//printf("%d %d %d %d %d %d\n", Keisuu1, Keisuu2, Keisuu3, Keisuu4, Keisuu5, Keisuu6);
					}
				}
			}
		}
	}
	*/

	/*
	int amari;
	int roku = N / 100001;
	amari = N % 100001;
	int go = amari / 10001;
	amari = amari % 10001;
	int yon = amari / 1001;
	amari = amari % 1001;
	int san = amari / 101;
	amari = amari % 101;
	int ni = amari / 11;
	for (int i = 0; i <= ni; i++) {
		//if (N == 1037) printf("%d %d\n", i, amari);
		int tmp = amari - 11 * i;
		if (0 <= tmp && tmp <= 18 && tmp % 2 == 0) {
			(*depth)++;
			Solve(roku * 100000 + go * 10000 + yon * 1000 + san * 100 + i * 10 + tmp / 2, depth);
		}
	}
	*/
}

int N;
vector<map<int, int>> X;

ll ans = 0;
void DFS(vector<int> tmp, ll depth) {
	if (depth == N) {
		vector<int> ok(N, -1);
		for (int i = 0; i < N; i++) {
			ok[i] = tmp[i];
		}
		for (int i = 0; i < N; i++) {
			if (tmp[i] == 1) {
				for (auto it = X[i].begin(); it != X[i].end(); it++) {
					int f = it->first;
					int s = it->second;
					
					if (ok[f] != s) return;//NG;
				}
			}
		}

		ll tmpv = 0;
		for (auto x : tmp)
			if (x == 1) tmpv++;

		ans = max(ans, tmpv);

		return;
	}

	for (int i = 0; i < 2; i++) {
		vector<int> next_tmp;
		for (auto x : tmp) {
			next_tmp.push_back(x);
		}
		next_tmp.push_back(i);
		DFS(next_tmp, depth + 1);
	}
}


int main(void) {
	cin.tie(0);
	ios::sync_with_stdio(false);
	//Program Start	

	cin >> N;
	X.resize(N);
	
	rep(i, N) {
		int A;
		cin >> A;
		rep(j, A) {
			int x, y;
			cin >> x >> y;
			x--;
			X[i].emplace(x, y);
		}
	}

	DFS(vector<int>(), 0);

	cout << ans << endl;

ProgramEndPointLabel:;

	//Program End
#ifndef DEBUG
	system("pause");
#endif // !DEBUG


	return 0;
}




Measured memory_bytes: 504