构图比较巧妙,添加超级源点和汇点
某个屋子第一次被打开则在源点与当前顾客添加边,容量为此屋子初始猪数量。 再次被打开时在上一个打开此屋子的人与当前顾客添加边,容量无穷。在每个顾客与汇点间加边,容量为此顾客买猪数目。 之后就是模板了。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int MAXN=105;
const int EM=200005;
const int INF=0x7fffffff;
int first[MAXN],dist[MAXN],size;
int Q[MAXN],p[1005],val[1005];
int s,t,N,M;
struct Edge
{
int v,c,next;
}edge[EM];
void insert(int u,int v,int c)
{
edge[size].v=v;
edge[size].c=c;
edge[size].next=first[u];
first[u]=size++;
}
int dinic_bfs()
{
int head=0,tail=0;
memset(dist,0,sizeof(dist));
dist[s]=1; Q[tail++]=s;
while(head<tail)
{
int u=Q[head++],v;
for(int e=first[u];e!=-1;e=edge[e].next)
{
if(edge[e].c && !dist[v=edge[e].v])
{
dist[v]=dist[u]+1;
if(v==t) return 1;
Q[tail++]=v;
}
}
}
return 0;
}
int dinic_dfs(int u,int cap)
{
int ret=0,v;
if(u==t) return cap;
for(int e=first[u];e!=-1;e=edge[e].next)
{
if(edge[e].c && dist[v=edge[e].v]==dist[u]+1 && ret<cap)
{
int flow=dinic_dfs(v,min(cap-ret,edge[e].c));
if(flow>0)
{
edge[e].c-=flow;
edge[e^1].c+=flow;
ret+=flow;
}
}
}
if(!ret) dist[u]=-1;
return ret;
}
int dinic()
{
int ans=0,tmp;
while(dinic_bfs())
while(tmp=dinic_dfs(s,INF)) ans+=tmp;
return ans;
}
int main()
{
// freopen("test.txt","r",stdin);
scanf("%d%d",&M,&N);
for(int i=1;i<=M;i++)
scanf("%d",&val[i]);
memset(first,-1,sizeof(first));size=0;
memset(p,0,sizeof(p));
for(int i=1;i<=N;i++)
{
int A,B,u;
scanf("%d",&A);
for(int j=0;j<A;j++)
{
scanf("%d",&u);
insert(p[u],i,val[u]);
insert(i,p[u],0);
p[u]=i;val[u]=INF;
}
scanf("%d\n",&B);
insert(i,N+1,B);
insert(N+1,i,0);
}
s=0;t=N+1;
printf("%d\n",dinic());
return 0;
}