poj 3281 Dining //SAP

Dining
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 3803   Accepted: 1723

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.

Source

USACO 2007 Open Gold

以前做的题目,拆点有的是因为是无向图,有的是因为防止回流

这一次这个题目的拆点,是因为每头牛只能吃一个套餐。

这是一个很关键的因素,这个因素也限制了二分图匹配的应用

我不知道哪位高手是用二分图解掉这道题,但我在思考用二分图建图的时候,就受这个条件的制约,转而去寻找用网络流的方法

 

构图还是比较简单的

很容易就得到左边放食物,右边放饮料

刚开始我用二分图做的时候,就是直接按照牛的喜好,将食物和饮料相连

后来因为二分图这条路走不通,使用SAP的时候,那么关键就变成了满足上面那个每头牛只吃一个套餐的条件了。

那怎么满足呢?

对,就是将牛拆点,拆i,i+f,两个点之间练1,保证每头牛只能吃一次。

其他就是源点连向食物,边长为1;饮料连向汇点,边长为1.

构图就是这样了,比较简单

 

如果谁知道怎么用二分图过了这道题,跟我说一声,谢了 

 

#include<cstdio>

#include<cstring>

const int N=510;

const int M=100001;

const int inf=0x7fffffff;

int head[N];

struct Edge

{

    int v,next,w;

} edge[M];

int cnt,n,s,t;

void addedge(int u,int v,int w)

{

    edge[cnt].v=v;

    edge[cnt].w=w;

    edge[cnt].next=head[u];

    head[u]=cnt++;

    edge[cnt].v=u;

    edge[cnt].w=0;

    edge[cnt].next=head[v];

    head[v]=cnt++;

}

int sap()

{

    int pre[N],cur[N],dis[N],gap[N];

    int flow=0,aug=inf,u;

    bool flag;

    for(int i=0; i<n; i++)

    {

        cur[i]=head[i];

        gap[i]=dis[i]=0;

    }

    gap[s]=n;

    u=pre[s]=s;

    while(dis[s]<n)

    {

        flag=0;

        for(int &j=cur[u]; j!=-1; j=edge[j].next)

        {

            int v=edge[j].v;

            if(edge[j].w>0&&dis[u]==dis[v]+1)

            {

                flag=1;

                if(edge[j].w<aug) aug=edge[j].w;

                pre[v]=u;

                u=v;

                if(u==t)

                {

                    flow+=aug;

                    while(u!=s)

                    {

                        u=pre[u];

                        edge[cur[u]].w-=aug;

                        edge[cur[u]^1].w+=aug;

                    }

                    aug=inf;

                }

                break;

            }

        }

        if(flag) continue;

        int mindis=n;

        for(int j=head[u]; j!=-1; j=edge[j].next)

        {

            int v=edge[j].v;

            if(edge[j].w>0&&dis[v]<mindis)

            {

                mindis=dis[v];

                cur[u]=j;

            }

        }

        if((--gap[dis[u]])==0)

            break;

        gap[dis[u]=mindis+1]++;

        u=pre[u];

    }

    return flow;

}

int main()

{

    int f,d;

    while(scanf("%d%d%d",&n,&f,&d)!=EOF)

    {

        int ff,dd;

        s=0;

        t=d+f+2*n+1;

        cnt=0;

        memset(head,-1,sizeof(head));

        for(int i=1;i<=f;i++) addedge(0,i,1);

        for(int i=1;i<=n;i++) addedge(i+f,i+n+f,1);   //2*n+f

        for(int i=1;i<=d;i++) addedge(i+f+2*n,d+f+2*n+1,1);

        for(int i=1;i<=n;i++)

        {

            int x;

            scanf("%d%d",&ff,&dd);

            for(int j=1;j<=ff;j++)

            {

                scanf("%d",&x);

                addedge(x,i+f,1);

            }

            for(int j=1;j<=dd;j++)

            {

                scanf("%d",&x);

                addedge(i+n+f,x+f+2*n,1);

            }

        }

        n=d+f+2*n+2;

        printf("%d/n",sap());

    }

    return 0;

}

你可能感兴趣的:(struct,Integer,SAP,each,output,Types)