二分图的最大匹配,加一个源点,这个源点到左边所有顶点加一条边,权值为1. 。同理,加一个终点,所有右边的定点到这个终点有条边,权值为1. 这样二分图的最大匹配就转换成了最大流问题。
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=405;
int cap[MAX][MAX]={0};
int flow[MAX][MAX]={0};
int pre[MAX],m[MAX];
int N, M,S,T;
const int INF=10000000;
int bfs(int s)
{
    memset(m,0,sizeof m);  
    memset(pre,0,sizeof pre);
    queue<int> q;
    q.push(s);
    m[s]=INF;
    while(!q.empty())
    {
            int u=q.front(); q.pop();
            for(int v=0; v<=N+M+1; v++)
                    if(!m[v]&&cap[u][v]>flow[u][v])
                    {
                         pre[v]=u;
                         m[v]= m[u]>cap[u][v]-flow[u][v]?cap[u][v]-flow[u][v]:m[u];
                         q.push(v);
                    }
    }
    
   if(m[T]==0)return 0;
   
   for(int u=T; u!=S ; u=pre[u])
   {
           flow[pre[u]][u]+=m[T];
           flow[u][pre[u]]-=m[T];
   }
   return m[T];
}
int main()
{
    
    while(cin>>N>>M)
    {    memset(cap,0,sizeof cap);
         memset(flow,0,sizeof flow);
         for(int i=1; i<=N; i++)
         {
            int c,e;
            cin>>c;
            for(int j=1; j<=c; j++)
                   {
                         cin>>e;
                         e=e+N;
                         cap[i][e]=1;
                   } 
         } 
         S=0; 
         T=N+M+1;
         for(int i=1; i<=N; i++)
            cap[0][i]=1;
            
         for(int i=1; i<=M; i++)
            cap[N+i][T]=1;
    
         int ans=0;
         while(1)
         {
            int temp=bfs(S);
            if(temp==0)break;
            else ans+=temp;
         }
    
         cout<<ans<<endl;
    }   
    system("pause");
    return 0;
}