有一个国家采取全民教育、自主选择的方式,尽可能多的将高中毕业的学生安排进大学进行学习(国家只会安排学生进入他们希望进入的大学,而不会让他们进入自己不想去的学校)。但是,在此之前,所有的高中毕业生,需要先填写自己希望进入的大学的报考编号,我们称之为——填志愿。但是最终每个学生只能被其中一所大学录取。请你帮助计算今年在这个国家,最多能有多少个高中毕业学生进入大学学习。
输入格式:
第1行包括两个整数,N和M,分别表示今年高中毕业生的数量与今年招生的大学的数量(0≤N,M≤200)。
输入第2行-输入第N+1行,每行对应一个毕业生今年填写的志愿,每行第一个数字表示学生填写的想去的大学的总数S,后面S个数分别为这些大学的报考编号(每行的数字都由空格分隔,0≤S≤M)。
输出格式:
第一行输出一个整数,表示在满足学生零个或一个填报志愿进行录取的情况下,国家最多可以安排多少将高中毕业的学生安排进大学进行学习。
样例输入
5 5 2 2 5 3 2 3 4 2 1 5 3 1 2 5 1 2
样例输出
4
思路:二分图最大匹配,设置各超级源点超级汇点,然后直接跑网络流就行了。
另外......每个大学居然只收一名学生。真是奇妙的学校......
代码如下:
#include <bits/stdc++.h>
#define inf 10007
using namespace std;
int n,m,E;
int G[505][505],layer[505];
bool find_layer(){
memset(layer,-1,sizeof(layer));
queue<int>q;
while(!q.empty())q.pop();
q.push(0);
layer[0]=0;
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=1;i<=E;i++){
if(G[now][i] && layer[i]==-1){
layer[i]=layer[now]+1;
q.push(i);
if(i==E)return true;
}
}
}
return false;
}
int Dinic(){
deque<int>dq;
while(!dq.empty())dq.pop_back();
int vis[505];
memset(vis,0,sizeof(vis));
int ans=0;
while(find_layer()){
memset(vis,0,sizeof(vis));
vis[0]=1;
dq.push_back(0);
while(!dq.empty()){
if(dq.back()==E){
int Min=inf,Min_s;
for(int i=1;i<dq.size();i++){
int s=dq[i-1],e=dq[i];
if(G[s][e]<Min){
Min=G[s][e];
Min_s=s;
}
}
ans+=Min;
for(int i=1;i<dq.size();i++){
int s=dq[i-1],e=dq[i];
G[s][e]-=Min;
G[e][s]+=Min;
}
while(!dq.empty() &&dq.back()!=Min_s){
vis[dq.back()]=0;
dq.pop_back();
}
}
else{
int flag=1;
for(int i=1;i<=E;i++){
if(G[dq.back()][i] && !vis[i] && layer[i]==layer[dq.back()]+1){
flag=0;
vis[i]=1;
dq.push_back(i);
break;
}
}
if(flag)dq.pop_back();
}
}
}
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
E=n+m+1;
memset(G,0,sizeof(G));
for(int i=1;i<=n;i++){
int k;
scanf("%d",&k);
for(int j=1;j<=k;j++){
int t;
scanf("%d",&t);
G[i][t+n]=1;
}
G[0][i]=1;
}
for(int i=1;i<=m;i++)G[n+i][E]=1;
cout<<Dinic()<<endl;
}
}