poj1149

来源:互联网 发布:软件项目合同书 编辑:程序博客网 时间:2024/06/05 20:17

PIGS
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 17297 Accepted: 7841

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 33 1 102 1 2 22 1 3 31 2 6

Sample Output

7

题目大意:m个猪圈,n个人先后来买猪,每个人会选择若干个猪圈购买,一定个数的猪(购买力),购买完剩余的猪可以分配到猪圈(必须是这个人选择的猪圈)。

问n个人最多能购买多少猪?

一个想法就是对猪圈按照买的人顺序拆分,方法和我之前做过的“家园”类似,传送门:家园 

但这只是想法,如果这么做图会非常庞大,这是网络流算法必定超时,于是想要合并点。

这些都是技巧问题,可以上网查查资料。

我把最后转化出的简化模型说一下:

对每个猪圈都有一个购买序列(人的编号),对于每个猪圈的第一人,他将有权支配该猪圈的所有猪,也就是从源点连接这个人,权值就是该猪圈的猪的数量;对于每个猪圈的第i(i>1)人,显然该猪圈已被前i-1人打开,因此

这i-1人都拥有将他们能支配的猪放到该猪圈的权利,换句话说,该猪圈此时可以拥有的猪的数量为这些人能支配的猪的总数,也就是从这i-1人出发,每个人连向第i人,边权为无穷大,这样表示这些人能支配的猪都可以流向第i人,最后对于每一个人都有一条边连向汇点,边权就是他们各自的购买力。然后一遍最大流即可。这里采用Edmonds_Karp算法。

代码:

#include<iostream>#include<cstdio>#include<vector>#include<cstring>#define Maxn 110using namespace std;const int inf=0x3f3f3f3f;int cap[Maxn][Maxn];int flow[Maxn][Maxn];int pre[Maxn];int alpha[Maxn];int q[Maxn];int m,n;int num[Maxn*10],buy[Maxn];vector<int> dv[Maxn*10]; //猪圈购买顾客顺序void init(){    memset(cap,0,sizeof cap);    memset(flow,0,sizeof flow);}int Edmonds_Karp(int src,int t){    int maxflow=0;    while(1){        memset(alpha,0,sizeof alpha);        alpha[src]=inf;        pre[src]=-1;        int s=0,e=-1;        q[++e]=src;        while(s<=e&&!alpha[t]){            int u=q[s++];            for(int i=0;i<=n+1;i++){                if(!alpha[i]&&flow[u][i]<cap[u][i]){                    pre[i]=u;                    alpha[i]=min(alpha[u],cap[u][i]-flow[u][i]);                    q[++e]=i;                }            }        }        if(!alpha[t]) break;        int k=t;        while(pre[k]!=-1){            flow[pre[k]][k]+=alpha[t];            flow[k][pre[k]]-=alpha[t];            k=pre[k];        }        maxflow+=alpha[t];    }    return maxflow;}int main(){    int z,x;    while(cin>>m>>n){        init();        for(int i=1;i<=m;i++){            dv[i].clear();            scanf("%d",num+i);        }        for(int i=1;i<=n;i++){            scanf("%d",&z);            for(int j=0;j<z;j++){                scanf("%d",&x);                dv[x].push_back(i);            }            scanf("%d",buy+i);        }        for(int i=1;i<=m;i++){            cap[0][dv[i][0]]+=num[i]; //每个猪圈第一个顾客            for(int j=1;j<dv[i].size();j++)                for(int k=0;k<j;k++)                    cap[dv[i][k]][dv[i][j]]=inf;        }        for(int i=1;i<=n;i++)            cap[i][n+1]+=buy[i];        printf("%d\n",Edmonds_Karp(0,n+1));    }    return 0;}


0 0