POJ3281 拆点 最大流 EK算法

来源:互联网 发布:酒店网络机顶盒案例 编辑:程序博客网 时间:2024/05/16 18:57
Dining
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 17948 Accepted: 8013

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 32 2 1 2 3 12 2 2 3 1 22 2 1 3 1 22 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.


今天开始刷kuangbin的最大流专题 发现根本做不动...

这道题也是网上查看了题解才会做的

思路:

建立一个超级源点和一个超级汇点 源点用编号0表示 汇点用2*n+f+d+1表示 

食物用1~f 表示 饮料用2*n+f+1~2*n+f+d表示 

将牛拆点 拆为两组 第一组编号为f+1~f+n 第二组为 f+n+1~f+2*n 自己与自己相连

将源点与食物相连 食物再与第一组牛相连 第一组牛与第二组牛相连 第二组牛与饮料相连(边的权值也为1) 再将饮料连到汇点

这样的作用是什么呢  例如1号牛与1号牛自己相连(也就是结点f+1与结点f+n+1相连) 并把这条边的值设置为1

这就表明 流在流的过程中 第二组牛只能只能选择1杯饮料 因为f+1到f+n+1这条边最大的流量就是1

这样就解决了一只牛可以对应多杯饮料的情况


#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<string>#include<stack>#include<queue>#include<cmath>#include<stack>#include<list>#include<map>#include<set>typedef long long ll;using namespace std;int cap[405][405];int pre[405];int flow[405];int m;int bfs(int s,int e){    queue<int>q;    int i;    memset(pre,-1,sizeof pre);    flow[s]=0x3f3f3f3f;    pre[s]=0;    q.push(s);    while(!q.empty())    {        int k=q.front();        q.pop();        if(k==e)break;        for(i=0;i<=e;i++)        {            if(i!=s&&pre[i]==-1&&cap[k][i])            {                pre[i]=k;                flow[i]=min(flow[k],cap[k][i]);                q.push(i);            }        }    }    if(pre[e]==-1)return -1;    return flow[e];}int max_flow(int s,int e){    int inc=0;    int flow1=0;    while((inc=bfs(s,e))!=-1)    {        int k=e;        while(k!=s)        {            int last=pre[k];            cap[last][k]-=inc;            cap[k][last]+=inc;            k=last;        }        flow1+=inc;    }    return flow1;}int main(){    int n,f,d;    int i,j,k;    while(scanf("%d%d%d",&n,&f,&d)==3)//f是食物 d是饮料    {        memset(cap,0,sizeof cap);        memset(flow,0,sizeof flow);        int source=0; //源点        int sink=2*n+f+d+1; //汇点        for(i=1;i<=f;i++) cap[source][i]=1;  //食物 是1到f        for(i=2*n+f+1;i<=2*n+f+d;i++)cap[i][sink]=1; //饮料是 2*n+f+1 到2*n+f+d        for(i=f+1;i<=f+n;i++)cap[i][i+n]=1; //牛与牛自己相连        for(i=1;i<=n;i++)        {            int drink,eat;            scanf("%d%d",&eat,&drink);            while(eat--)            {                int t;                scanf("%d",&t);                cap[t][i+f]=1;            }            while(drink--)            {                int t;                scanf("%d",&t);                cap[f+n+i][2*n+f+t]=1;            }        }         m=sink;         printf("%d\n",max_flow(source,sink));    }    return 0;}



原创粉丝点击