2010成都赛区网络赛第五题---Food(hdu4292)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4292

    题意:有F种食物和D种饮料和他们的具体数量。有N个人,每个人喜欢其中的某些食物或饮料,如何分配这些食物和饮料,能让更多的人,得到他们喜欢的一种食物和饮料。

     思路:网络流。

     建图思路:

           (1)、取超级源点和超级汇点。

           (2)、拆点,将一个人拆成i点和i'点,在i与i'之间建立一条容量为1的边。           

                   (3)、在源点和食物之间建立一条边,容量为各自的数量。

            (4)、在饮料和汇点之间建立一条边,容量为各自的数量。

            (5)、在食物和i点之间建立一条边,容量为1。

                    (6)、在i'点和饮料之间建立一条边,容量为1。

代码:(该代码在hdu上用G++能过,用C++报错,求高人指点)

#include <stdio.h>
#include <string.h>
#define MAXN 11000
#define INF 0x3f3f3f3f
struct Edge{
    int u;
    int v;
    int cap;
    int next;
}edge[MAXN*40];
int cur[MAXN],head[MAXN],level[MAXN],gap[MAXN];
int stack[MAXN],que[MAXN];
int tot;
void Ini()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int from,int to,int cap)
{
    edge[tot].u = from;
    edge[tot].v = to;
    edge[tot].cap = cap;
    edge[tot].next = head[from];
    head[from] = tot;
    tot++;
    
    edge[tot].u = to;
    edge[tot].v = from;
    edge[tot].cap = 0;
    edge[tot].next = head[to];
    head[to] = tot;
    tot++;
}
void bfs(int src,int des)
{
    
    int i;
    int front,rear;
    memset(gap,0,sizeof(gap));
    memset(level,-1,sizeof(level));
    front = rear = 0;
    level[des] = 0;
    gap[0] = 1;
    que[rear++] = des;
    while(front != rear)
    {
        int u = que[front++];
        front = front%MAXN;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            int v = edge[i].v;
            if(edge[i].cap != 0 || level[v] != -1)
                continue;
            level[v] = level[u]+1;
            que[rear++]=v;
            rear = rear%MAXN;
            ++gap[level[v]];
        }
    }
}
int sap(int src,int des)
{

    bfs(src,des);
    int i;
    int res=0;
    memcpy(cur,head,sizeof(head));
    int top=0;
    int u = src;
    while(level[src] < des+1)
    {
        if(u == des)
        {
            int temp = INF;
            int inser;
            for(i=0;i<top;i++)
            {
                if(temp > edge[stack[i]].cap)
                {
                    temp = edge[stack[i]].cap;
                    inser = i;
                }
            }
            for(i=0;i<top;i++)
            {
                edge[stack[i]].cap -= temp;
                edge[stack[i] ^ 1].cap += temp;
            }
            res += temp;
            top = inser;
            u = edge[stack[top]].u;
        }
        if(u != des && gap[level[u]-1] == 0)
            break;
        for(i=cur[u];i!=-1;i = edge[i].next)
            if( edge[i].cap != 0 && level[u] == level[edge[i].v]+1)
                break;

        if(i != -1)
        {
            cur[u] = i;
            stack[top++] = i;
            u = edge[i].v;
        }

        else
        {
            int min=des+1;
            for(i=head[u];i!=-1;i=edge[i].next)
            {
                if(edge[i].cap == 0)
                    continue;
                if(min > level[edge[i].v])
                {
                    min = level[edge[i].v];
                    cur[u] = i;
                }
            }
            --gap[level[u]];
            level[u] = min + 1;
            ++gap[level[u]];
            if(u!=src)
                u = edge[stack[--top]].u;
        }
    }
    return res;
}
int main()
{
    int i,j;
    int N,F,D;
    int food;
    int drink;
    char str[250];
    while(scanf("%d%d%d",&N,&F,&D)!=EOF)
    {
       Ini();
       int src= 0;
       int des = 2*N + F + D +1;
       for(i=1;i<=F;i++)
       {
           scanf("%d",&food);
           addedge(src,i,food);

       }
       for(i=F+2*N+1;i<=F+2*N+D;i++)
       {
            scanf("%d",&drink);
            addedge(i,des,drink);
       }
       for(i=F+1;i<=F+N;i++)
           addedge(i,i+N,1);
        for(i=1;i<=N;i++)
        {
            scanf("%s",str+1);
            for(j=1;j<=F;j++)
            {
                if(str[j] == 'Y')
                    addedge(j,F+i,1);
            }
        }
        for(i=1;i<=N;i++)
        {
            scanf("%s",str+1);
            for(j=1;j<=D;j++)
            {
                if(str[j] == 'Y')
                    addedge(F+N+i,F+2*N+j,1);
            }
        }
        printf("%d\n",sap(src,des));
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值