POJ 1149 PIGS (最大流)

PIGS
Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 13538Accepted: 5973

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
 
经典构图题。首先源点和每个人连边,权值为人的购买量;其次人与猪圈连边,容量为无穷大;然后猪圈与汇点连边,容量为猪圈内猪的数量;最后对于当前人,如果他能开的猪圈之前有人开过,那么将这人与之前能开这个猪圈的人连边,权值为无穷大。最后直接跑ISAP。

 

//340 KB	0 ms	
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define SIZE 1111
#define inf 0x7fffffff

using namespace std;

struct node
{
    int to,val,next;
}edge[SIZE*111];

int M,N,sc,sk,pt;
int head[SIZE],idx;
bool cnt[111][SIZE];
int dis[SIZE],gap[SIZE];

void addnode(int from,int to,int val)
{
    edge[idx].to = to;
    edge[idx].val = val;
    edge[idx].next = head[from];
    head[from] =  idx ++;
    edge[idx].to = from;
    edge[idx].val = 0;
    edge[idx].next = head[to];
    head[to] = idx ++;
}

int dfs(int cur,int cval)
{
    if(cur == sk)
        return cval;
    int mindis = pt - 1, tval = cval;
    for(int i=head[cur]; i!=-1; i=edge[i].next)
    {
        int to = edge[i].to;
        if(edge[i].val > 0)
        {
            if(dis[to] + 1 == dis[cur])
            {
                int val = dfs(to,min(edge[i].val,tval));
                tval -= val;
                edge[i].val -= val;
                edge[i^1].val += val;
                if(dis[sc] >= pt)
                    return cval-tval;
                if(tval == 0)
                    break;
            }
            if(dis[to] < mindis)
                mindis = dis[to];
        }
    }
    if(cval == tval)
    {
        --gap[dis[cur]];
        if(!gap[dis[cur]])
            dis[sc] = pt;
        dis[cur] = mindis + 1;
        ++gap[dis[cur]];
    }
    return cval-tval;
}

void sap()
{
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    int ret = 0;
    gap[sc] = pt;
    while(dis[sc] < pt)
        ret += dfs(sc,inf);
    printf("%d\n",ret);
}

void read()
{
    idx = 0;
    sc = 0, sk = N+M+1, pt = sk+1;
    memset(head,-1,sizeof(head));
    memset(cnt,0,sizeof(cnt));
    int A,B,t;
    for(int i=1; i<=M; i++)
    {
        scanf("%d",&t);
        addnode(N+i,sk,t);
    }
    for(int i=1; i<=N; i++)
    {
        scanf("%d",&A);
        for(int j=1; j<=A; j++)
        {
            scanf("%d",&t);
            cnt[i][t] = true;
            for(int k=i-1; k>=1; k--)
            {
                if(cnt[k][t])
                    addnode(i,k,inf);
            }
            addnode(i,N+t,inf);
        }
        scanf("%d",&B);
        addnode(sc,i,B);
    }
}

int main()
{
    while(~scanf("%d%d",&M,&N))
    {
        read();
        sap();
    }
    return 0;
}


 


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值