#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MAX1 305
#define MAX2 305
int n,m,match[MAX2]; //二分图的两个集合分别含有n和m个元素。
bool visit[MAX2],G[MAX1][MAX2]; //G存储邻接矩阵。
bool DFS(int k)
{ int t;
for(int i = 0; i < m; i++)
{ if(G[k][i] && !visit[i])
{ visit[i] = true; t = match[i]; match[i] = k; //路径取反操作。
if(t == -1 || DFS(t)) return true; //整个算法的核心部分
match[i] = t;
}
}
return false;
}
int Max_match ()
{ int ans = 0,i;
memset(match, -1, sizeof(match));
for(i = 0; i <n ;i++)
{ memset(visit,0,sizeof(visit));
if(DFS(i)) ans++;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,i,j,p,q;
while(scanf("%d",&n)!=EOF)
{
memset(G,false,sizeof(G));
m=305;
for(i=0;i<n;i++)
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&p,&q);
G[i][(p-1)*12+q]=true;
}
}
printf("%d\n",Max_match());
}
return 0;
}
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MAX1 305
#define MAX2 305
int n,m,match[MAX2]; //二分图的两个集合分别含有n和m个元素。
bool visit[MAX2],G[MAX1][MAX2]; //G存储邻接矩阵。
bool DFS(int k)
{ int t;
for(int i = 0; i < m; i++)
{ if(G[k][i] && !visit[i])
{ visit[i] = true; t = match[i]; match[i] = k; //路径取反操作。
if(t == -1 || DFS(t)) return true; //整个算法的核心部分
match[i] = t;
}
}
return false;
}
int Max_match ()
{ int ans = 0,i;
memset(match, -1, sizeof(match));
for(i = 0; i <n ;i++)
{ memset(visit,0,sizeof(visit));
if(DFS(i)) ans++;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,i,j,p,q;
while(scanf("%d",&n)!=EOF)
{
memset(G,false,sizeof(G));
m=305;
for(i=0;i<n;i++)
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&p,&q);
G[i][(p-1)*12+q]=true;
}
}
printf("%d\n",Max_match());
}
return 0;
}