POJ 3281 /// 最大流

题目大意:

n 头牛 f 种食物 d 种饮料

每头牛有各自喜欢的食物和饮料

求最多有多少头牛能分配到自己喜欢的食物和饮料

因为同时有食物和饮料 所以不能用二分图匹配

 用最大流解决二分图匹配的办法

增加一个源点连向所有食物 每头牛与各自喜欢的食物连边 

增加一个汇点连向所有的饮料 每头牛与各自喜欢的饮料连边

以上边容量都为1

单纯这样连的话 一头牛可能分配到多种食物和饮料

把一头牛拆成两个点 一点与食物连边 另一点与饮料连边

再在两个点之间连一条容量为1的边 这样就能保证只有一个流量流过

即只有一种食物被选 饮料反过来同理

此时从源点到汇点跑个最大流就能得到答案

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=105;
bool F[N][N], D[N][N];
int n, f, d;

struct EDGE { int v,c,r; };
vector <EDGE> E[505];
bool vis[505];
void addE(int u,int v,int c) {
    E[u].push_back((EDGE){v,c,E[v].size()});
    E[v].push_back((EDGE){u,0,E[u].size()-1});
}
/**最大流*/
int dfs(int s,int t,int f) { 
    if(s==t) return f;
    vis[s]=1;
    for(int i=0;i<E[s].size();i++) {
        EDGE& e=E[s][i]; // EDGE& 之后可直接修改到这个地址的数值
        if(!vis[e.v] && e.c>0) { // 没走过且可流过
            int d=dfs(e.v,t,min(f,e.c)); // 继续搜 能流过的最大流量
            if(d>0) { // 说明可流过d流量
                e.c-=d; // 那么这条边的剩余容量减小
                E[e.v][e.r].c+=d; // 反向边剩余容量变大
                return d;
            }
        }
    }
    return 0;
}
int maxFlow(int s,int t) {
    int flow=0;
    while(1) {
        memset(vis,0,sizeof(vis));
        int f=dfs(s,t,INF); // 边的容量改变后 继续搜
        // 边的容量改变后就可能会走反向边 
        // 走反向边意味着 反悔正向的流量(可能有浪费)
        // 即 把正向的流量调小
        if(f==0) return flow; //  直到不可流
        flow+=f;
    }
}
/***/

/*  0~n-1 食物一侧的牛
    n~2*n-1 饮料一侧的牛
    2*n~2*n+f-1 食物
    2*n+f~2*n+f+d-1 饮料
*/
void solve() {
    // 增加一个源点 s=2*n+f+d
    // 增加一个汇点 t=s+1
    int s=2*n+f+d, t=s+1;
    for(int i=0;i<=t;i++) E[i].clear();
    for(int i=2*n;i<2*n+f;i++)
        addE(s,i,1); // 源点到食物
    for(int i=2*n+f;i<2*n+f+d;i++)
        addE(i,t,1); // 饮料到汇点
    for(int i=0;i<n;i++) {
        addE(i,i+n,1); // 一头牛拆成的两个点连边
        for(int j=0;j<f;j++)
            if(F[i][j]) addE(2*n+j,i,1); // 食物到牛的一点
        for(int j=0;j<d;j++)
            if(D[i][j]) addE(n+i,2*n+f+j,1); // 另一点到饮料
    }
    printf("%d
",maxFlow(s,t));
}
int main()
{
    while(~scanf("%d%d%d",&n,&f,&d)) {
        memset(F,0,sizeof(F));
        memset(D,0,sizeof(D));
        for(int i=0;i<n;i++) {
            int a,b,t; scanf("%d%d",&a,&b);
            while(a--) {
                scanf("%d",&t); F[i][t-1]=1;
            }
            while(b--) {
                scanf("%d",&t); D[i][t-1]=1;
            }
        }
        solve();
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zquzjx/p/10122294.html