#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <stack>
#include <vector>

using namespace std;

typedef long long LL;
typedef vector<LL> VL;
typedef vector<vector<LL>> VVL;
typedef vector<vector<char>> VVC;
typedef vector<string> VS;

#define REPD(i,a,b) for (LL i=(a);i<(b);i++)
#define REP(i,n) REPD(i,0,n)

LL llRead(){
  LL a;
  cin >> a;
  return a;
};

string stringRead(){
  string a;
  cin >> a;
  return a;
};

vector<LL> vlRead(LL a){
  vector<LL> rv;
  REP(i, a){
    LL input;
    cin >> input;
    rv.push_back(input);
  }
  return rv;
}

vector<string> vsRead(LL a){
  vector<string> rv;
  REP(i, a){
    string input;
    cin >> input;
    rv.push_back(input);
  }
  return rv;
}
VVL vvlRead(LL a, LL b){
  vector<vector<LL>> rv;
  REP(i, a){
    rv.push_back(vector<LL>());
    REP(j, b) {
      LL input;
      cin >> input;
      rv.at(i).push_back(input);
    }
  }
  return rv;
}

VVC vvcRead(LL a, LL b){
  VVC rv;
  REP(i, a){
    rv.push_back(vector<char>());
    REP(j, b) {
      char input;
      cin >> input;
      rv.at(i).push_back(input);
    }
  }
  return rv;
}

#if 0
#define DEBUG_VECTOR_NEWLINE

#define debug(d) debug1(__LINE__,#d, d)
void debug1(LL line, const char* name, VL& v) {
  cout << line << ":" << name << ":vector<LL>(" << v.size() << ") ";
  REP(i, (LL)v.size()) {
    cout << v.at(i) << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, double i) {
  cout << line << ":" << name << ":double " << i << endl;;
}
void debug1(LL line, const char* name, LL i) {
  cout << line << ":" << name << ":LL " << i << endl;;
}
void debug1(LL line, const char* name, VS& v) {
  cout << line << ":" << name << ":vector<string>(" << v.size() << ") ";
  REP(i, (LL)v.size()) {
    cout << v.at(i) << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, vector<bool>& v) {
  cout << line << ":" << name << ":vector<bool>(" << v.size() << ") ";
  REP(i, (LL)v.size()) {
    cout << v.at(i) << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, VVL& v) {
  cout << line << ":" << name << ":vector<vector<LL>>(" << v.size() << ") ";
#ifdef DEBUG_VECTOR_NEWLINE
  cout << endl;
#endif
  REP(i, (LL)v.size()) {
    REP(j, (LL)v.at(i).size()) {
      cout << v.at(i).at(j) << " ";
    }
    cout << ", ";
#ifdef DEBUG_VECTOR_NEWLINE
    cout << endl;
#endif
  }
  cout << endl;
}
void debug1(LL line, const char* name, VVC& v) {
  cout << line << ":" << name << ":vector<vector<char>>(" << v.size() << ") ";
#ifdef DEBUG_VECTOR_NEWLINE
  cout << endl;
#endif
  REP(i, (LL)v.size()) {
    REP(j, (LL)v.at(i).size()) {
      cout << v.at(i).at(j) << " ";
    }
    cout << ", ";
#ifdef DEBUG_VECTOR_NEWLINE
    cout << endl;
#endif
  }
  cout << endl;
}
void debug1(LL line, const char* name, char* s) {
  cout << line << ":" << name << ":char* " << s << endl;;
}
void debug1(LL line, const char* name, vector<const char*>& v) {
  cout << line << ":" << name << ":vector<const char*>(" << v.size() << ") ";
  REP(i, (LL)v.size()) {
    cout << v.at(i) << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, priority_queue<LL>& p) {
  cout << line << ":" << name << ":priority_queue<LL>(" << p.size() << ") ";
  priority_queue<LL> copy = p;
  while(!copy.empty()) {
    cout << copy.top() << " ";
    copy.pop();
  }
  cout << endl;
}
void debug1(LL line, const char* name, vector<pair<LL,LL>>& v) {
  cout << line << ":" << name << ":vector<pair<LL,LL>>(" << v.size() << ") ";
  REP(i, (LL)v.size()) {
    cout << v.at(i).first << "," << v.at(i).second << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, map<LL,LL>& m) {
  cout << line << ":" << name << ":map<LL,LL>(" << m.size() << ") ";
  for (auto p : m) {
    cout << p.first << "," << p.second << " ";
  }
  cout << endl;
}
void debug1(LL line, const char* name, multimap<LL,LL>& m) {
  cout << line << ":" << name << ":map<LL,LL>(" << m.size() << ") ";
  for (auto p : m) {
    cout << p.first << "," << p.second << " ";
  }
  cout << endl;
}
#else
#define debug(n)
#endif

#define BASE (1000000007)

LL factm(LL n) {
  debug(n);
  LL ret = 1;
  REPD(i,2,n+1) {
    ret*=i;
    ret=ret%BASE;
  }
  debug(ret);
  return ret;
}

LL inv(LL a) {
    LL b = BASE, u = 1, v = 0;
    while (b) {
        LL t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    u %= BASE;
    if (u < 0) u += BASE;
    return u;
}
int main(int argc, const char * argv[]) {
	cout.precision(16);
  // source code

  auto N = llRead();
  vector<vector<pair<LL,LL>>> data;
  REP(i,N) {
    LL c = llRead();
    data.push_back(vector<pair<LL,LL>>());
    REP(j,c) {
      LL x = llRead();
      LL y = llRead();
      data[i].push_back(make_pair(x,y));
    }
  }

  /*
  vector<bool> answer;
  REP(i,N) {
    answer.push_back(false);
  }

  auto validp = [&](LL i) {
    REP(i,N) {
      if (answer[i]) {
        REP(j, data[i].size()) {
          auto c = data[i][j];
          if (c.second == 1) {
            if (!answer[c.first-1]) return false;
          } else {
            if (answer[c.first-1]) return false;
          }
        }
      }
    }
    return true;
  };

  function<LL(LL)> findMax = [&](LL base) {
    debug(answer);
    LL mmax = base;
    REP(i,N) {
    debug(i);
      if (answer[i]) {
      } else {
        answer[i] = true;
        if (validp(i)) {
          debug("valid");
          LL r = findMax(base+1);
          mmax = r<mmax?mmax:r;
        }
        answer[i] = false;
      }
    }
    return mmax;
  };
  cout << findMax(0) << endl;
*/

  /*
  vector<bool> answer;
  REP(i,N) {
    answer.push_back(true);
  }

  auto validp = [&]() {
    REP(i,N) {
      if (answer[i]) {
        REP(j, data[i].size()) {
          auto c = data[i][j];
          if (c.second == 1) {
            if (!answer[c.first-1]) return false;
          } else {
            if (answer[c.first-1]) return false;
          }
        }
      }
    }
    return true;
  };

  function<LL(LL)> findMax = [&](LL base) {
    debug(answer);
    if (validp()) return base;
    LL mmin = N;
    REP(i,N) {
    debug(i);
      if (answer[i]) {
        answer[i] = false;
        LL c = findMax(base+1);
        mmin = mmin<c?mmin:c;
        answer[i] = true;
      }
    }
    return mmin;
  };
  cout << N-findMax(0) << endl;
  */

  auto validp = [&](LL t) {
    REP(i,N) {
      if (((1<<i)&t) != 0) {
        REP(j, data[i].size()) {
          auto c = data[i][j];
          if (c.second == 1) {
            if (((1<<(c.first-1))&t) == 0) return false;
          } else {
            if (((1<<(c.first-1))&t) != 0) return false;
          }
        }
      }
    }
    return true;
  };
  LL mmax = 0;
  for (LL i=0;i<(1<<N);i++) {
    debug(i);
    LL bits = 0;
    REP(j, N) {
      if (((1<<j)&i) != 0) bits++;
    }
    if (bits < mmax) continue;
    if (validp(i)) {
      debug(i);
      debug(bits);
      debug(mmax);
      mmax = bits;
    }
  }
  cout << mmax << endl;
  return 0;
}


Measured memory_bytes: 256