计蒜客 填志愿 解题报告

有一个国家采取全民教育、自主选择的方式,尽可能多的将高中毕业的学生安排进大学进行学习(国家只会安排学生进入他们希望进入的大学,而不会让他们进入自己不想去的学校)。但是,在此之前,所有的高中毕业生,需要先填写自己希望进入的大学的报考编号,我们称之为——填志愿。但是最终每个学生只能被其中一所大学录取。请你帮助计算今年在这个国家,最多能有多少个高中毕业学生进入大学学习。

输入格式:

    第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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值