[POJ1149]PIGS 做题笔记

18 篇文章 0 订阅
3 篇文章 0 订阅

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

这题的一个技巧:网络流的+oo容量边可以传递流量。
除了每个猪圈的第一个顾客,每个猪圈的顾客都可以获得这个猪圈的上一个顾客所能获得的所有的猪,因为上一个顾客来了后,在极端情况下可以把他所能获得的所有的猪都调到当前顾客光顾的猪圈。
有了这个思路,我们新建超级源汇,S到第一个光顾某猪圈的顾客连一条容量为该猪圈初始猪数目的边,如果这个顾客还能光顾其它猪圈并且这些猪圈也是第一次有人光顾,那么可以把这些边合并。
如果一个猪圈有人光顾了,那么从这个猪圈的上一个顾客到这个猪圈的当前顾客连一条容量+oo的边。
所有的顾客到T连容量为顾客要买的猪的数量的边。
然后跑一遍最大流。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N=200,M=30000,inf=0x3fffffff;
int pig[2000],last[2000];
int head[N],d[N],e[M],ver[M],next[M];
int tot=1,n,m,maxflow=0,s,t;

void add (int u,int v,int w) {
    ver[++tot]=v;e[tot]=w;next[tot]=head[u];head[u]=tot;
    ver[++tot]=u;e[tot]=0;next[tot]=head[v];head[v]=tot;
}

bool bfs () {
    queue<int> q;
    memset(d,0,sizeof(d));
    q.push(s); d[s]=1;
    while (!q.empty()) {
        int x=q.front(); q.pop();
        for (int i=head[x];i;i=next[i]) 
            if (e[i]&&!d[ver[i]]) {
                q.push(ver[i]);
                d[ver[i]]=d[x]+1;
                if (ver[i]==t) return 1;
            }
    }
    return 0;
}

int dinic (int x,int f) {
    int rest=f;
    if (x==t) return f;
    for (int i=head[x];i&&rest;i=next[i]) 
        if (e[i]&&d[ver[i]]==d[x]+1) {
            int now=dinic(ver[i],min(e[i],rest));
            if (!now) d[ver[i]]=0;//
            e[i]-=now;
            e[i^1]+=now;
            rest-=now;
        }
    return f-rest;
}

int main () {
    int k,x,w,tmp;
    scanf("%d%d",&m,&n);
    s=0;t=n+1;
    for (int i=1;i<=m;i++) 
        scanf("%d",&pig[i]);
    for (int i=1;i<=n;i++) {
        scanf("%d",&k);
        tmp=0;
        for (int j=1;j<=k;j++) {
            scanf("%d",&x);
            if (!last[x]) tmp+=pig[x];
            else add(last[x],i,inf);
            last[x]=i;
        }
        scanf("%d",&w);
        if (tmp) add(s,i,tmp);
        add(i,t,w);
    }
    while (bfs()) 
        while (tmp=dinic(s,inf)) maxflow+=tmp;
    printf("%d",maxflow);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值