POJ 3281 Dining(网络流,建图,dinic)

Dining

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 11828   Accepted: 5437

Description

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.

Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.

Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).

Input

Line 1: Three space-separated integers: NF, and D 
Lines 2..N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.

Output

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes

Sample Input

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

Sample Output

3

Hint

One way to satisfy three cows is: 
Cow 1: no meal 
Cow 2: Food #2, Drink #2 
Cow 3: Food #1, Drink #1 
Cow 4: Food #3, Drink #3 
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.

/*

农夫为他的 N (1 ≤ N ≤ 100) 牛准备了 F (1 ≤ F ≤ 100)种食物和 D (1 ≤ D ≤ 100) 种饮料。每头牛都有各自喜欢的食物和饮料,而每种食物或饮料只能分配给一头牛。最多能有多少头牛可以同时得到喜欢的食物和饮料?

Input

第一行输入三个整数N, F, D

接下来n行,每行先输入两个整数 Fi 和 Di,分别表示编号为 i 的牛喜欢的食物和饮料的数量,接下来的Fi个整数表示第i头牛喜欢的食物的编号,最后Di个整数表示第i头牛喜欢的饮料的编号。

Output

输出同时得到喜欢的食物和饮料的牛的数量的最大值。

*/

下方来自:https://blog.csdn.net/immortal_steller/article/details/20922069

 * 思路:
 * 本题关键是建图,图建完以后就是裸dinic
 * 建图方法,设1+F+D+2*N+1个结点,1表示源点,1+F+D+2*N+1表示汇点
 * 1+1 ~ 1+F表示食物结点,1+F+1 ~ 1+F+N表示牛的编号,1+F+N+1 ~ 1+F+2*N也表示牛的编号,为什么这样后面说明
 * 1+F+2*N+1 ~ 1+F+2*N+D表示饮料编号
 *
 * 然后被喜欢的食物指向喜欢它的牛的所有边,牛i指向牛i的所有边,牛指向它喜欢的饮料的所有边,源点到所有食物,饮料到所有汇点的边,权值全设为1
 *
 * 建图解释:
 * 首先,这幅图被分为几个模块,从左到右依次为:食物制作模块(src-F边集),喂食物模块(F-N1边集),牛吃食物模块(N1-N2边集),喂饮料模块(N2-D边集)和牛喝饮料模块(D-tar边集)
 * 然后解释为什么设权值为1,第一:人做的食物和水都是一份;第二:牛最多吃一份食物(水),就算有多份食物指向牛,由于下一条边(牛指出的边,即牛吃食物(喝饮料)模块)为1,意味着最后只能流出1的流量,即吃掉其中一份食物,水的指出同理
 * 这样就能想到为什么要设两次牛了,就是要通过牛-牛边控制流量为1,即通过食物选择模块后,保证一头牛只吃了一份食物
 * 然后吃完食物流量为1了,就只能选一条路喝饮料,最后饮料流出的也是唯一一条边,表示这种饮料最终只能被一头牛选择

1、若直接食物->牛->饮料

          食物             牛                   饮料

                   

如图,例如当1到4这条路走过后 4连上5,当2经过4后4又可以连上6,这就造成了一头牛吃了多种食物和饮料

2、食物->左牛->右牛->饮料

这种情况当左牛选中一个食物之后经过右牛,左右牛之间的路径已经满流不能继续走,就避免了一头牛吃多种食物和饮料的情况

 刚刚看懂的 ac代码。。。。。。。(╥╯^╰╥)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxx=100+100+2*100+100;
const int mod=1e9+7;
/*N头牛,F种食物 D种饮料*/
int F,D,N,g[maxx][maxx],lv[maxx];//深度
int bfs(int src,int tar)
{
    memset(lv,0,sizeof(lv));//初始化深度
    queue<int > que;
    que.push(src);
    lv[src]=1;
    while(!que.empty())
    {
        int cur=que.front();
        que.pop();
        for(int i=src;i<=tar;i++)
        {
            if(!lv[i]&&g[cur][i])
            {
                lv[i]=lv[cur]+1;
                que.push(i);
            }
        }
    }
    if(lv[tar]==0) return 0;
    return 1;
}
int dfs(int cur,int src,int tar,int totflow)
{
    int ans=0;
    if(cur==tar||!totflow)
        return totflow;
    for(int i=src;i<=tar;i++)
    {
        if(totflow==0) break;
        if(g[cur][i]&&(lv[cur]+1==lv[i]))
        {
            int f=min(totflow,g[cur][i]);
            int flowdown=dfs(i,src,tar,f);
            ans+=flowdown;
            totflow-=flowdown;
            g[cur][i]-=flowdown;
            g[i][cur]+=flowdown;
        }
    }return ans;
}
int dinic(int src,int tar)
{
    int ans=0;
    while(bfs(src,tar))
    {
        int temp=dfs(src,src,tar,D+F);
        if(!temp) break;
        ans+=temp;
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d%d",&N,&F,&D))
    {
        int src=1,tar=1+F+D+2*N+1;
        for(int i=1;i<=F;i++)//src-F 边集
        {
            g[src][src+i]=1;
        }
        for(int i=1+2*N+F+1;i<tar;i++)//D-tar边集
        {
            g[i][tar]=1;
        }
        for(int i=1;i<=N;i++)
        {
            g[src+F+i][src+F+i+N]=1;//N1-N2边集
            int fi,di;
            scanf("%d%d",&fi,&di);
            int temp;
            while(fi--)//F-N1边集
            {
                scanf("%d",&temp);
                g[src+temp][src+F+i]=1;
            }
            while(di--)
            {
                scanf("%d",&temp);//N2-D边集
                g[src+F+i+N][src+F+2*N+temp]=1;
            }
        }printf("%d\n",dinic(src,tar));
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40046426/article/details/81810478
今日推荐