C

题目大意:N头牛,F个食物,D个饮料。每一个食物和饮料只能分享给一头牛,每一头牛也最多获得一个饮料和一个食物,问最多有几头牛可以同时获得一个食物和一个饮料?

这是一个典型的最大流问题。难点在于建图,建完图就是最大流裸题了。

关于见图。

每头牛都有喜欢的食物和饮料,首先看对牛与食物和牛与饮料分别被建边。注意到饮料和食物是毫无关系的。食物是食物,饮料是饮料,并不能相互代替。因此我们见图的时候可以用食物指向牛,牛指向饮料(反过来也可以)。注意,每头牛最多获得一个食物和饮料,这时候就需要对顶点进行限流。即牛与牛之间要加一条边权为1的边。

最终建成的图应该是这样的:

 边均为有向边,方向均指向右方。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF=1e9+7;
const int N=1E4+7;
struct stu{
    int to,val,nxt;
}edge[N];
int n,f,d;
int dis[N];
int head[N],tol=0;
void add(int x,int y,int z){
    edge[tol].to=y;
    edge[tol].val=z;
    edge[tol].nxt=head[x];
    head[x]=tol++;
} 
bool bfs(int s,int t){
    for(int i=0;i<=n+n+f+d+1;i++) dis[i]=INF;
    queue<int>que;
    dis[s]=0;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            int w=edge[i].val;
            if(w>0&&dis[u]+1<dis[v]) {
                dis[v]=dis[u]+1;
                que.push(v);
            }
        }
    }
    return dis[t]!=INF;
}
int dfs(int s,int t,int  mn){
    if(s==t) return mn;
    for(int i=head[s];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        int w=edge[i].val;
        if(w<=0||dis[v]!=dis[s]+1) continue ;
        int cw=dfs(v,t,min(w,mn));
        if(cw>0){
            edge[i].val-=cw;
            edge[i^1].val+=cw;
            return cw;
        }
    }
    return 0;
}
void dicnic(int s,int t){
    int  ans=0;
    while(bfs(s,t)){
        int d;
        while((d=dfs(s,t,INF))!=0){
            ans+=d;
        }
    } 
    cout<<ans<<endl;
}
int main(){
    memset(head,-1,sizeof head);
    cin>>n>>f>>d;
    int s=0,t=n+n+f+d+1;//源点与汇点

    for(int i=1;i<=n;i++){//牛。
        int t1,t2,food,drink;
        cin>>t1>>t2;
        for(int j=1;j<=t1;j++){
            cin>>food;
            add(food+n+n,i,1);
            add(i,food+n+n,0);
        }
        for(int j=1;j<=t2;j++){
            cin>>drink; 
            add(i+n,drink+n+n+f,1);
            add(drink+n+n+f,i+n,0);
        }
    }
    for(int i=1;i<=n;i++){
        add(i,i+n,1);
        add(i+n,i,0);
    }
    for(int i=1;i<=f;i++){
        add(s,n+n+i,1);
        add(n+n+i,s,0);
    } 
    for(int i=1;i<=d;i++){
        add(n+n+f+i,t,1);
        add(t,n+n+f+i,0);
    }
    dicnic(s,t);
    return 0;
}
原文地址:https://www.cnblogs.com/Accepting/p/13372323.html