POJ1149:PIGS(最大流)

PIGS
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 21219 Accepted: 9688

Description

Mirko works on a pig farm that consists of M locked pig-houses and Mirko can't unlock any pighouse because he doesn't have the keys. Customers come to the farm one after another. Each of them has keys to some pig-houses and wants to buy a certain number of pigs. 
All data concerning customers planning to visit the farm on that particular day are available to Mirko early in the morning so that he can make a sales-plan in order to maximize the number of pigs sold. 
More precisely, the procedure is as following: the customer arrives, opens all pig-houses to which he has the key, Mirko sells a certain number of pigs from all the unlocked pig-houses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. 
An unlimited number of pigs can be placed in every pig-house. 
Write a program that will find the maximum number of pigs that he can sell on that day.

Input

The first line of input contains two integers M and N, 1 <= M <= 1000, 1 <= N <= 100, number of pighouses and number of customers. Pig houses are numbered from 1 to M and customers are numbered from 1 to N. 
The next line contains M integeres, for each pig-house initial number of pigs. The number of pigs in each pig-house is greater or equal to 0 and less or equal to 1000. 
The next N lines contains records about the customers in the following form ( record about the i-th customer is written in the (i+2)-th line): 
A K1 K2 ... KA B It means that this customer has key to the pig-houses marked with the numbers K1, K2, ..., KA (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0.

Output

The first and only line of the output should contain the number of sold pigs.

Sample Input

3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6

Sample Output

7

Source

题意:来自《网络流建模汇总》有M个猪圈,每个猪圈里初始时有若干头猪。一开始所有猪圈都是关闭的。依次来了N个顾客,每个顾客分别会打开指定的几个猪圈,从中买若干头猪。每个顾客分别都有他能够买的数量的上限。每个顾客走后,他打开的那些猪圈中的猪,都可以被任意地调换到其它开着的猪圈里,然后所有猪圈重新关上。问总共最多能卖出多少头猪。(1 <= N <= 100, 1 <= M <= 1000) 。

思路:对于第i个顾客选择的猪房a[0], a[1]...a[k],如果a[j]已经被前面某个顾客选择过了,那么顾客i可以分流到该前任顾客上,如果a[0~k]都没有被选择过,那么a[0~k]的猪房可以优化合并为1条路,具体参考《网络流建模汇总》。

# include <iostream>
# include <cstdio>
# include <queue>
# include <cstring>
using namespace std;

const int INF = 0x7fffffff;
int cnt=0, pig[2003], pre[2003], tmp[2003], Next[2003], dis[2003], q[2003];

struct node
{
    int e, w, next;
}edge[10000];

void add_edge(int u, int v, int w)
{
    edge[cnt].e = v;
    edge[cnt].w = w;
    edge[cnt].next = Next[u];
    Next[u] = cnt++;
    edge[cnt].e = u;
    edge[cnt].w = 0;
    edge[cnt].next = Next[v];
    Next[v] = cnt++;
}

bool bfs()
{
    memset(dis, -1, sizeof(dis));
    dis[0] = 0;
    int l=0, r=0;
    q[r++] = 0;
    while(l<r)
    {
        int u = q[l];
        ++l;
        for(int i=Next[u]; i!=-1; i=edge[i].next)
        {
            int v = edge[i].e, w = edge[i].w;
            if(w > 0 && dis[v]==-1)
            {
                dis[v] = dis[u] + 1;
                q[r++] = v;
            }
        }
    }
    return dis[1888] != -1;
}

int dfs(int u, int pre)
{
    if(u == 1888)
        return pre;
    int f=0,ans=0;
    for(int i=Next[u]; i!=-1; i=edge[i].next)
    {
        int v = edge[i].e, w = edge[i].w;
        if(w > 0 && dis[v]==dis[u]+1 && (f=dfs(v, min(w, pre))))
        {
            edge[i].w -= f;
            edge[i^1].w += f;
            ans += f;
            pre -= f;
            if(!pre)
                break;
        }
    }
    if(ans)
        return ans;
    dis[u] = -1;
    return 0;
}

int main()
{
    memset(pre, -1, sizeof(pre));
    memset(Next, -1, sizeof(Next));
    int n, m, c, id, buy;
    scanf("%d%d",&m,&n);
    for(int i=1; i<=m; ++i)
        scanf("%d",&pig[i]);
    for(int i=1; i<=n; ++i)
    {
        scanf("%d",&c);
        int num = 0, sum = 0;
        for(int j=0; j<c; ++j)
        {
            scanf("%d",&tmp[j]);
            if(pre[tmp[j]] == -1)
                ++num, sum += pig[tmp[j]], pre[tmp[j]] = i+1000;
        }
        if(num == c)
            add_edge(i+1000, 1888, sum);
        else
        {
            for(int j=0; j<c; ++j)
            {
                if(pre[tmp[j]] == i+1000)
                    add_edge(i+1000, tmp[j], INF), add_edge(tmp[j], 1888, pig[tmp[j]]);
                else
                    add_edge(i+1000, pre[tmp[j]], INF);
            }
        }
        scanf("%d",&buy);
        add_edge(0, i+1000, buy);
    }
    int ans = 0;
    while(bfs())
        ans += dfs(0, INF);
    printf("%d\n",ans);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值