N - PIGS


N - PIGS
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

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


题意:告诉你有M个猪圈(每个猪圈里的猪数量也告诉你)和N个顾客,每个顾客只能买其中某些猪圈里的猪,并且告诉了你每个顾客最多能买的猪。求最多能卖出多少猪


其中需要注意的就是,每个猪圈里的猪是可以相互移动的,也就是说虽然每个顾客只能买一些猪圈的猪,但实际上是可以把其他猪圈的猪算在这里面的。


网络流建图:

1、单独设置一个源点和一个汇点。


2、如果某个顾客可以买的猪圈还没有可以被其他顾客买(按输入顺序),那么就在源点和这个顾客的点之间连一条边,边权为该猪圈的猪数量,如果已经有一条边,那么就在原边权上加上该值


3、如果某个顾客(j)可以买的猪圈已经被其他顾客(i)购买,那么 cap[i][j] = INF; 因为可以看做j可以从i顾客那里无限买猪(因为猪圈的猪可以互相移动,我们一开始认为该猪圈所有的猪都被i顾客买了,所以j是从i那里买)


4、将所有顾客连一条边到汇点,边权为他能买的猪的上限。


在这样建立了一个图之后,我们使用最大流来跑一次就可以了。


#include"iostream"
#include"cstring"
#include"cstdio"
#include"queue"

#define MAXN 1005
#define INF 0x7f7f7f7f

using namespace std;

int num[MAXN];
int fir[MAXN];
int flow[MAXN][MAXN];
int cap[MAXN][MAXN];
int a[MAXN];
int p[MAXN];
int n,m;

int E_K(int s,int t)
{
    queue<int> q;
    memset(flow,0,sizeof(flow));
    int f = 0;
    while(true)
    {
        memset(a,0,sizeof(a));
        a[s] = INF;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int v = 0;v <= n+1;v++)
            {
                if(!a[v] && cap[u][v] > flow[u][v])
                {
                    p[v] = u;
                    q.push(v);
                    a[v] = (a[u] < cap[u][v] - flow[u][v] ? a[u] : cap[u][v] - flow[u][v]);
                }
            }
        }
        if(a[t] == 0) break;
        for(int u = t;u != s;u = p[u])
        {
            flow[p[u]][u] += a[t];
            flow[u][p[u]] -= a[t];
        }
        f += a[t];
    }
    return f;
}

int main(void)
{
    while(~scanf("%d%d",&m,&n))
    {
        memset(cap,0,sizeof(cap));
        memset(fir,-1,sizeof(fir));
        for(int i = 1;i <= m;i++) scanf("%d",&num[i]);
        for(int i = 1;i <= n;i++)
        {
            int A,B;
            scanf("%d",&A);
            while(A--)
            {
                int xx;
                scanf("%d",&xx);
                if(fir[xx] == -1)
                {
                    cap[0][i] += num[xx];
                    fir[xx] = i;
                }
                else
                {
                    cap[fir[xx]][i] = INF;
                }
            }
            scanf("%d",&B);
            cap[i][n+1] = B;
        }
        int ans = E_K(0,n+1);
        cout << ans << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值