#include <bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#include "debug.cpp"
#else
#endif
#define ll long long int
#define MOD 1000000007
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define INF 100000000000000 //INF - 1e14
#define vi vector<ll>
#define pb push_back
#define mpl map<ll,ll>
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vpll vector<pair<ll,ll> >
#define fer(i, a, n) for( ll i = a; i <= n; i++)
#define fdr(i, a, n) for( ll i = a; i >= n; i--)
#define invec(n,v) vi v(n); fer(i,0,n-1) cin >> v[i]
#define insvec(n,v) rin(n); vi v(n); fer(i,0,n-1) cin >> v[i]
#define MK2DV(v,row,col,val) vector<vector<ll> > v(row, vector<ll>(col,val))
#define matrix vector<vector<ll> >
#define printv(v,i,j) for(ll it =i; it <= j; it++) cout << v[it] << ' '; cout << '\n';
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
template <typename T> inline void inp(T &any) {cin >> any;} template <typename T, typename... U>inline void inp(T &a, U &...b) {cin >> a; inp(b...);}
#define rin(args...) ll args; inp(args);
#ifndef ONLINE_JUDGE
#define debug(x...) cout << "[" << #x << "] = ["; _print(x)
#define matdeb(mat,row,col) cout << #mat << "::" << endl; printmat(mat,row,col); printpartition;
#define debugv(v,n) cout << #v << ":" << endl; printv(v,0,n-1); printpartition;
#else
#define debug(x...)
#define matdeb(mat,row,col)
#define debugv(v,n)
#endif
ll fast_pow(ll base, ll exp, ll M = MOD) { base = base % M; ll result = 1; while (exp > 0) { if (exp % 2 == 1) result = (result * base) % M; base = (base * base) % M; exp = exp / 2; } return result; }
ll modInverse(ll A, ll M = MOD) { return fast_pow(A, M - 2, M); } // only when M is prime
ll lcm(ll x, ll y) { return x / __gcd(x, y) * y;}
void coordinatecompress(vector<ll> &data) { ll n = data.size(); vector<pair<ll, ll> > tempdata(n); fer(i, 0, n - 1) tempdata[i] = {data[i], i}; sort(tempdata.begin(), tempdata.end()); data[tempdata[0].second] = 0; fer(i, 1, n - 1) data[tempdata[i].second] = data[tempdata[i - 1].second] + (tempdata[i - 1].first != tempdata[i].first); }
string yes = "Yes", no = "No";
// void dfs(ll s, ll p) {
// 	for (auto nbr : adj[s]) {
// 		if (nbr != p) {
// 			dfs(nbr, s);
// 		}
// 	}
// }
int main() {
	ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#ifndef ONLINE_JUDGE
	// freopen("intt.txt", "r", stdin);
	// freopen("outt.txt", "w", stdout);
#endif
	int n;
	cin >> n;
	vector<vector<pair<int, int> > > v(n);
	for (int i = 0; i < n; i++) {
		int sz;
		cin >> sz;
		v[i].resize(sz);
		for (int j = 0; j < sz; j++) {
			cin >> v[i][j].first >> v[i][j].second;
			v[i][j].first--;
		}
	}
	int mask = (1 << n) - 1;
	while (mask > 0) {
		// debug(mask);
		// how to check if a mask is valid??
		// every true guy in that mask must not say that the mask guys are false
		int ppl = mask;
		int i = n - 1;
		// debug(ppl);
		bool poss = true;
		while (ppl) {
			// debug(i, (bool)(ppl & 1));
			if (ppl & 1) {
				// ith banda is speaking the truth
				// see his testimonies
				for (auto p : v[i]) {
					int id = n - 1 - p.first;
					if (p.second) {
						// acc to testimony p.first is truthful
						// if this is not in mask then poss=false
						// n-1-p.first
						if (!((1 << id)&mask)) {
							// debug(id, mask, "not present");
							poss = false;
						}
						// if(mask&(1<<p))
					}
					else {
						if (((1 << id)&mask)) {
							// debug(id, mask, "present");
							poss = false;
						}
					}
				}

			}
			ppl /= 2;
			i--;
		}
		if (poss) {
			// debug(mask, "poosss");
			break;
		}
		mask--;
	}
	cout << __builtin_popcount(mask);
	// debug(mask, 1 );
	// for (auto p : v) {
	// 	debug(p);
	// }



	return 0;
}


Measured memory_bytes: 3616