/*
输入格式:
第1行3个整数,V1,V2的节点数目n1,n2,G的边数m
第2-m+1行,每行两个整数t1,t2,代表V1中编号为t1的点和V2中编号为t2的点之间有边相连
输出格式:
1个整数ans,代表最大匹配数
*/
#include <iostream>
using namespace std;
int n1,n2,m,ans;
int n;
int resultt[501]; //记录v2中匹配点的编号
bool state[501]; //记录v2中每个点是否被搜索过
bool data[501][501];//记录边的信息
void init()
{
int t1,t2;
memset(data,0,sizeof(data));
memset(resultt,0,sizeof(resultt));
ans=0;
int idd;
int i;
int linksum;
for(i=0;i<n;i++)
{
scanf("%d: (%d)",&idd,&linksum);
int i2;
int linkn;
for(i2=0;i2<linksum;i2++)
{
scanf("%d",&linkn);
data[idd][linkn]=true;
}
}
return;
}
bool find(int a)
{
for(int i=0;i<n;i++) //这里的i要是未盖点
{
if(data[a][i]==1&&!state[i]) //如果结点i与a相邻并且未被访问过
{
state[i]=true; //标记i为已查找
if(resultt[i]==0||find(resultt[i])) //i未在前一个匹配中或i在前一个匹配中但从i结点出发还有增广路
{
resultt[i]=a;
return true;
}
}
}
return false;
}
int main(int argc, char *argv[])
{
while(cin>>n)
{
int num=n;
int i;
init();
for(int i=0;i<n;i++)
{
memset(state,0,sizeof(state));
if(find(i))
{
ans+=1;
}
}
cout<<num-ans/2<<endl;
}
return 0;
}