POJ3281:Dining(dinic+拆点)

题目链接:http://poj.org/problem?id=3281

PS:刷够网络流了,先这样吧,之后再刷,慢慢补。

题意:有F种食物,D种饮料,N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份),一种食物被一头牛吃了之后,其余牛就不能吃了 第一行有N,F,D三个整数:接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类 要求输出最多分配能够满足的牛的数量.

思路:这是一种神奇的建图方式-拆点。让我想打死都想不出来。sad

建图,有2*n+f+d+2个顶点,0表示源点,2*n+f+d+1表示汇点。 由源点指向食物,再由食物指向牛,牛再指向对应的饮料,饮料再指向汇点 当然要使每一头牛都对应每一份食物与饮料,所以应该牛i指向牛i再指向饮料,这样就可以避免一头牛只占用多份食物与饮料了 全部是有向的边,而且权值全部为1 我在这里是1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点

 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <math.h>
#define N 1100
#define inf 0x3f3f3f3f
typedef int ll;
using namespace std;
ll n,f,d,tt,dis[N],head[N];
struct node
{
    ll x,y,w,next;
} eg[N*N];
void init()
{
    tt=0;
    memset(head,-1,sizeof(head));
}
void add(int xx,int yy)
{
    eg[tt].x=xx;
    eg[tt].y=yy;
    eg[tt].w=1;
    eg[tt].next=head[xx];
    head[xx]=tt++;
    eg[tt].x=yy;
    eg[tt].y=xx;
    eg[tt].w=0;
    eg[tt].next=head[yy];
    head[yy]=tt++;
}
bool bfs(int s,int e)
{
    memset(dis,-1,sizeof(dis));
    dis[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int fa=q.front();
        q.pop();
        for(int i=head[fa]; i!=-1; i=eg[i].next)
        {
            int v=eg[i].y;
            if(dis[v]==-1&&eg[i].w)
            {
                dis[v]=dis[fa]+1;
                q.push(v);
            }
        }
    }
    if(dis[e]>0)
        return true;
    return false;
}
int dinic(int s,int maxt)
{
    if(s==2*n+f+d+1) return maxt;
    int a,sum=maxt;
    for(int i=head[s]; i!=-1; i=eg[i].next)
    {
        int v=eg[i].y;
        if(dis[v]==dis[s]+1&&eg[i].w>0)
        {
            a=dinic(v,min(sum,eg[i].w));
            eg[i].w-=a;
            eg[i+1].w+=a;
            sum-=a;
        }
    }
    return maxt-sum;
}
int main()
{
    ll xx,yy,s1,s2;
    scanf("%d%d%d",&n,&f,&d);

        init();
        for(int j=1;j<=f;j++)
        {
            add(0,j);
        }
        for(int j=1;j<=d;j++)
        {
            add(f+2*n+j,f+2*n+d+1);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&s1,&s2);
            for(int j=1;j<=s1;j++)
            {
                scanf("%d",&xx);
                add(xx,f+i);
            }
            for(int j=1;j<=s2;j++)
            {
                scanf("%d",&yy);
                add(f+n+i,f+2*n+yy);
            }
        }
        for(int i=1;i<=n;i++)
        {
            add(f+i,f+n+i);
        }
        ll ans=0;
        while(bfs(0,2*n+f+d+1))
        {
            ans+=dinic(0,inf);
        }
        printf("%d\n",ans);

    return 0;
}

 

posted @ 2015-01-27 14:30  人艰不拆_zmc  阅读(252)  评论(0编辑  收藏  举报