【最大流 && 拆点限流】POJ

来源:互联网 发布:淘宝禁售商品答案 编辑:程序博客网 时间:2024/05/26 05:52

Problem Dscription

输入 n, f, d分别代表有n头牛,f种食物,d种饮料。接下来n行,每行输入F D f[1]..f[F] d[1]..d[D]。代表牛1有F种喜欢的食物,D种喜欢的饮料,分别是f[1]..f[F], d[1]..d[D]。每种食物只能给一个牛吃,每种饮料也只能给一个牛喝,意思就是给了牛A,就不能给牛B了。问你最多有多少头牛。能吃到食物同时喝到饮料?

思路:

核心是建图参考了挑战P235页。设置一个超级汇点0,和超级源点2*n+f+d+1。牛分为1 到 n,n+1 到 n+n两个点。食物2*n+1 到 2*n+f。 饮料2*n+f+1 到 2*n+f+d。
超级源点到所有食物连边流量为1。所有的饮料到超级汇点连边流量为1。食物到牛第一个点连边,按照题目所给,流量为1。牛得拆分成两个点目的是为了限制到牛的流量只能是1,所以拆成两个点连边流量为1。牛第二个点到饮料连边,按照题目所给,流量为1。然后求最大流就好了。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{    int to, w, next;};node Map[50000];int head[500], vis[500], cnt;int dfs(int s, int t, int f){    vis[s] = 1;    if(s == t) return f;    for(int i = head[s]; ~i; i = Map[i].next)    {        int to = Map[i].to, &w = Map[i].w;        if(!vis[to] && w)        {            int d = dfs(to, t, min(f, w));            if(d > 0)            {                w -= d;                Map[i^1].w += d;                return d;            }        }    }    return 0;}int ek(int s, int t){    int Max_flow = 0;    for(;;)    {        memset(vis, 0, sizeof(vis));        int d = dfs(s, t, 0x3f3f3f3f);        if(d == 0) break;        Max_flow += d;    }    return Max_flow;}void add(int u, int v, int w)//前向星{    Map[cnt].to = v;    Map[cnt].w = w;    Map[cnt].next = head[u];    head[u] = cnt++;    Map[cnt].to = u;    Map[cnt].w = 0;    Map[cnt].next = head[v];    head[v] = cnt++;}int main(){    int n, f, d, F, D, food, drink;    while(~scanf("%d %d %d", &n, &f, &d))    {        cnt = 0;        memset(head, -1, sizeof(head));        for(int i = 1; i <= f; i++)//超级源点到食物            add(0, 2*n+i, 1);        for(int i = 1; i <= d; i++)//饮料到超级汇点            add(2*n+f+i, 2*n+f+d+1, 1);        for(int i = 1; i <= n; i++)        {            add(i, i+n, 1);//牛到牛之间            scanf("%d %d", &F, &D);            while(F--)            {                scanf("%d", &food);                add(2*n+food, i, 1);//食物到牛第一个点            }            while(D--)            {                scanf("%d", &drink);                add(i+n, 2*n+f+drink, 1);//牛第二个点到饮料            }        }        printf("%d\n", ek(0, 2*n+f+d+1));//输出最大流    }    return 0;}