题目大意:
迈克有个养猪场,养猪场里有M个猪圈,每个猪圈都上了锁。迈克没有钥匙,而要买猪的顾客一个接一个来到养猪场,
每个顾客有一些猪圈的钥匙,要买一定数量的猪。当每个顾客来时,将有钥匙的猪圈全部打开,从中挑出一些买走,
然后迈克可以重新分配这些猪圈里面的猪。当顾客离开后,门又被锁上。问迈克最多可以卖多少猪。
分析 :
(1)将顾客看做是除了源点和汇点以外的结点,并且另外设两个结点:源点和汇点。
(2)源点和每个猪圈的第1个顾客连边,边的权是开始时猪圈中猪的数量。
(3)若源点和每个结点之间有重边,可以合并。
(4)顾客j紧跟顾客i之后打开猪圈,则边的权是正无穷大,因为如果j紧跟i之后打开,迈克可以根据j的需求将其他猪圈调到该猪圈,
这样顾客j就可以买到尽可能多的猪。已开启的数目可以随意变动,如果打开过则与上一个打开的顾客连一条正无穷的边,
(5)每个顾客和汇点之间连边,表示顾客希望买猪的数目。
迈克有个养猪场,养猪场里有M个猪圈,每个猪圈都上了锁。迈克没有钥匙,而要买猪的顾客一个接一个来到养猪场,
每个顾客有一些猪圈的钥匙,要买一定数量的猪。当每个顾客来时,将有钥匙的猪圈全部打开,从中挑出一些买走,
然后迈克可以重新分配这些猪圈里面的猪。当顾客离开后,门又被锁上。问迈克最多可以卖多少猪。
分析 :
(1)将顾客看做是除了源点和汇点以外的结点,并且另外设两个结点:源点和汇点。
(2)源点和每个猪圈的第1个顾客连边,边的权是开始时猪圈中猪的数量。
(3)若源点和每个结点之间有重边,可以合并。
(4)顾客j紧跟顾客i之后打开猪圈,则边的权是正无穷大,因为如果j紧跟i之后打开,迈克可以根据j的需求将其他猪圈调到该猪圈,
这样顾客j就可以买到尽可能多的猪。已开启的数目可以随意变动,如果打开过则与上一个打开的顾客连一条正无穷的边,
(5)每个顾客和汇点之间连边,表示顾客希望买猪的数目。
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=500;
const int M=10000;
const int inf=1<<30 ;
struct node
{
int u,v,c,next;
}edge[M];
int pre[N],cur[N],gap[N],dis[N],head[N];
int has[M],pig[M];
int top ;
void add(int u, int v ,int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
int sap(int s,int t,int nv)
{
int flow=0,max_flow=inf,u,v;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for(int i=0; i<nv; i++) cur[i]=head[i];
gap[s]=nv;
u=pre[s]=s;
while(dis[s]<nv)
{
loop :
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
v=edge[j].v;
if(edge[j].c>0&&dis[u]==dis[v]+1)
{
if(edge[j].c<max_flow) max_flow=edge[j].c;
pre[v]=u;
u=v;
if(v==t)
{
for(u=pre[v];v!=s;v=u,u=pre[u])
{
edge[cur[u]].c-=max_flow;
edge[cur[u]^1].c+=max_flow;
}
flow+=max_flow;
max_flow=inf;
}
goto loop ;
}
}
int mindis=nv;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
v=edge[j].v;
if(edge[j].c>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
int m,n,A,sum,k,B;
while(~scanf("%d%d",&m,&n))
{
int s=0,t=n+1;
top=0;
memset(head,-1,sizeof(head));
memset(has,0,sizeof(has));
for(int i = 1 ; i <= m ; i++)
scanf("%d",&pig[i]);
for(int i = 1 ; i <= n ; i++)
{
sum=0;
scanf("%d",&A);
while(A--)
{
scanf("%d",&k);
if(!has[k]) sum+=pig[k];
else add(has[k],i,inf); //i紧跟上一个顾客选,连无穷边。
has[k]=i; //更新,k猪圈正被i顾客选。
}
add(s,i,sum); //i顾客有sum可以选;sum<B时,还可以从它上一个顾客与它连的边提供。
scanf("%d",&B); //i顾客只选B只。
add(i,t,B);
}
int ans=sap(s,t,t+1);
printf("%d\n",ans);
}
return 0;
}