#include #include #include #include using namespace std; typedef vector edges; typedef vector graph; graph g; vector visited; vector left, right; int N; int M; bool augment(int l) { if(!visited[l]){ visited[l] = true; edges &es = g[l]; for(int i = 0; i < es.size(); ++i){ // DFS-driven int r = es[i]; if(r == ::left[l]) continue; if(::right[r] == -1 || augment(::right[r])){ ::right[r] = l; ::left[l] = r; return true; } } } return false; } int matching(void) { int matched = 0; ::right.assign(M, -1); ::left.assign(N, -1); for(int i = 0; i < N; ++i){ visited.assign(N, false); if(augment(i)) ++matched; } return matched; } int main(void) { ifstream cin("guardian.in"); int NCase; cin >> NCase; for(int cases = 0; cases < NCase; ++cases){ int people; cin >> people; vector heights(people); vector sex(people); vector music(people); vector sports(people); for(int i = 0; i < people; ++i){ cin >> heights[i] >> sex[i] >> music[i] >> sports[i]; } vector leftmem, rightmem; N = M = 0; for(int i = 0; i < people; ++i){ if(sex[i] == 'M'){ leftmem.push_back(i); ++N; }else{ rightmem.push_back(i); ++M; } } g.clear(); g.resize(N); for(int i = 0; i < N; ++i){ int ii = leftmem[i]; for(int j = 0; j < M; ++j){ int jj = rightmem[j]; // danger edge if(abs(heights[ii] - heights[jj]) < 40 && music[ii] == music[jj] && sports[ii] != sports[jj]){ g[i].push_back(j); // cout << "edge from " << i << " " << j << endl; } } } int ncover = matching(); cout << people - ncover << endl; } return 0; }