POJ 3281:最大流

来源:互联网 发布:网络驱动器重启后没了 编辑:程序博客网 时间:2024/06/15 20:18

题意:有N个牛,F个食物,D个饮料,每个牛喜欢一些食物和饮料,现在要给牛分发食物和饮料,当一个牛得到一个喜欢的食物和一个喜欢的饮料的时候,就说这个牛被满足了。求最多可以满足多少个牛。每个饮料和食物只能被分给一个牛,每个牛也只能拿到一个饮料和食物。


题解:按流建图,一个合法的流应该是:一个牛以及一个喜欢的饮料一个喜欢的食物。一头牛贡献一单位的流量,所以把牛拆了,中间加一个1容量的边,然后起点到所有饮料连1容量边,饮料到喜欢自己的牛连1容量边,牛到他喜欢的食物连1容量的边,所有食物向终点连1容量的边。这样一个流就必须经过 饮料-牛-食物,且这个饮料和食物都是牛喜欢的,而且把牛拆了可以起到流量限制的作用,使得一个牛只占有一个饮料和食物,不会暴饮暴食(雾。


Code:

#include<cstdio>#include<cstring>#include<queue>using namespace std;const int maxn = 105;int tot,first[maxn*4],nxt[maxn*maxn*16],des[maxn*maxn*16],flow[maxn*maxn*16];int dep[maxn*4];const int INF = 0x3f3f3f3f;int d,f,n;int ss,tt;inline void addEdge(int x,int y,int z){tot++;des[tot] =y;flow[tot] =z;nxt[tot] = first[x];first[x] = tot;tot++;des[tot] =x;flow[tot] =0;nxt[tot] = first[y];first[y] =tot;}void input(){memset(first,-1,sizeof first);scanf("%d%d%d",&n,&f,&d);for (int i=1;i<=n;i++){int di,fi,x;scanf("%d%d",&fi,&di);for (int j=0;j<fi;j++){scanf("%d",&x);addEdge(2*n+x,i,1);}for (int j=0;j<di;j++){scanf("%d",&x);addEdge(n+i,2*n+f+x,1);}}for (int i=1;i<=f;i++){addEdge(0,2*n+i,1);}for (int i=1;i<=d;i++){addEdge(2*n+f+i,2*n+f+d+1,1);}for (int i=1;i<=n;i++){addEdge(i,i+n,1);}}bool bfs(){queue<int> Q;memset(dep,-1,sizeof dep);dep[ss] =0;Q.push(ss);while (!Q.empty()){int q = Q.front();Q.pop();for (int t = first[q];t!=-1;t=nxt[t]){int v = des[t];int c = flow[t];if (c&&dep[v]==-1){dep[v] = dep[q]+1;Q.push(v);}}}return dep[tt]!=-1;}int dfs(int node,int now){if (node==tt)return now;int ret =0;for (int t = first[node];t!=-1&&ret<now;t= nxt[t]){int v = des[t];int c = flow[t];if (c&&dep[v]==dep[node]+1){int x = min(c,now-ret);x = dfs(v,x);flow[t]-=x;flow[t^1]+=x;ret +=x;}}if (!ret) dep[node] =-1;return ret;}int max_flow(){int tot =0;while (bfs()){int del =0;while (del = dfs(ss,INF)){tot+=del;}}return tot;}void solve(){ss =0;tt =2*n+f+d+1;printf("%d\n",max_flow());}int main(){tot =-1;input();solve();return 0;}


原创粉丝点击