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
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.
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 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.
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 6Sample Output
7
题意:n个顾客,m个猪圈,开始猪圈都关闭,每个顾客来了,他有某些猪圈的钥匙,他从这些猪圈中买猪,但数量有限定,在下一个顾客来之前,这些猪圈剩下的猪可以互换猪圈,求最多能卖多少猪;
思路:主要是建图难,这题用下面的规律就可以了
规律 1. 如果几个节点的流量的来源完全相同,则可以把它们合并成一个。
规律 2. 如果几个节点的流量的去向完全相同,则可以把它们合并成一个。
规律 3. 如果从点 u 到点 v 有一条容量为 +∞ 的边,并且 u 是 v 的唯一流量来源,或者 v 是 u 的唯一流量去向,则可以把 u 和 v 合并成一个节点
构图文章:http://wenku.baidu.com/view/0ad00abec77da26925c5b01c.html
然后下面主要是SAP的模板了,学习了一波,当图复杂就很实用了,虽然这道题,EK算法也很快
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1005;
const int M=20010;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
struct node
{
int from,to,next,w;
}edge[M];
int head[N],cur[N],dep[N],stacks[N],gap[N],vis[N],flag[N];
int ans,tot;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(stacks,-1,sizeof(stacks));
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
}
void add(int u,int v,int w)
{
edge[tot].from=u;
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
edge[tot].from=v;
edge[tot].to=u;
edge[tot].w=0;
edge[tot].next=head[v];
head[v]=tot++;
}
int pig[N];
void SAP(int s,int t,int n)
{
ans=0;
for(int i=0;i<=n;i++)
cur[i]=head[i];
gap[0]=n;
int i,u=s,top=0;
while(dep[s]<n)
{
if(u==t)//增广路计算流量stacks存路径
{
int temp=inf,num;
for(i=0;i<top;i++)
{
if(temp>edge[stacks[i]].w)
{
temp=edge[stacks[i]].w;
num=i;
}
}
for(i=0;i<top;i++)
{
edge[stacks[i]].w-=temp;
edge[stacks[i]^1].w+=temp;
}
ans+=temp;
top=num;//这条边容量为0
u=edge[stacks[top]].from;
}
for(i=cur[u];i!=-1;i=edge[i].next)
if(edge[i].w&&dep[u]==dep[edge[i].to]+1)
break;
if(i!=-1)//找到可行弧
{
cur[u]=i;
stacks[top++]=i;
u=edge[i].to;
}
else
{
int mins=n;
for(i=head[u];i!=-1;i=edge[i].next)//寻找最小dep
{
if(edge[i].w==0) continue;
if(mins>dep[edge[i].to])
{
mins=dep[edge[i].to];
cur[u]=i;
}
}
if(0==--gap[dep[u]])//gap判断,出现断层,跳出循环,相较于EK的优化地方
break;
dep[u]=mins+1;
++gap[dep[u]];
if(u!=s) //由于无可行弧往前推
u=edge[stacks[--top]].from;
}
}
}
int main()
{
int m,n,s,e;
while(~scanf("%d%d",&m,&n))
{
init();
s=n+1;
e=s+1;
for(int i=1;i<=m;i++)
scanf("%d",&pig[i]);
for(int k=1;k<=n;k++)
{
int a,b,p;
scanf("%d",&a);
for(int i=1;i<=a;i++)
{
scanf("%d",&p);
if(!vis[p])//猪圈v没有被开过
{
if(!flag[k])//顾客k没有开过猪圈
{
add(s,k,pig[p]);
flag[k]=tot-2;
}
else
edge[flag[k]].w+=pig[p];
vis[p]=k;
}
else
{
add(vis[p],k,inf);
vis[p]=k;
}
}
scanf("%d",&b);
add(k,e,b);
}
SAP(s,e,e);
printf("%d\n",ans);
}
return 0;
}