[POJ1149]PIGS 做题笔记

来源:互联网 发布:小知不及大知怎么读 编辑:程序博客网 时间:2024/04/29 20:00

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);}
0 0
原创粉丝点击