构图:源点向每个顾客连买猪数目的边,若顾客是第一个来到该猪圈的,则像猪圈连一条猪圈猪数目的边
,否则像上一个来到该猪圈的顾客连一条inf的边,猪圈向汇点连接一条猪圈猪数目的边,最大流
用了dinic算法
#include<stdio.h>
#include<string.h>
using namespace std;
const int inf=1<<30;
const int maxn=2001;
int a[maxn];
struct
{
int to,w,next;
}e[300001];
int lon=1,head[maxn];
int edgeini(int n)
{
for(int i=0;i<n;i++) head[i]=-1;
}
int edgemake(int from,int to,int w)
{
e[++lon].to=to;
e[lon].w=w;
e[lon].next=head[from];
head[from]=lon;
e[++lon].to=from;
e[lon].w=0;
e[lon].next=head[to];
head[to]=lon;
}
int level[maxn];
int makelevel(int s,int t)
{
memset(level,0,sizeof(level));
level[s]=1;
int top=0;
int que[maxn];
que[++top]=s;
for(int i=1;i<=top;i++)
{
int u=que[i];
// printf("%d %d\n",u,level[u]);
if(u==t) return(1);
for(int k=head[u];k!=-1;k=e[k].next)
if(!level[e[k].to]&&e[k].w)
{
que[++top]=e[k].to;
level[e[k].to]=level[u]+1;
}
}
return(0);
}
int dfs(int now,int maxf,int t)
{
if(now==t) return(maxf);
int ret=0;
for(int k=head[now];k!=-1;k=e[k].next)
{
if(e[k].w&&level[e[k].to]==level[now]+1)
{
int f=dfs(e[k].to,min(maxf-ret,e[k].w),t);
e[k].w-=f;
e[k^1].w+=f;
ret+=f;
// printf("%d %d\n",ret,maxf);
if(ret==maxf) return(ret);
}
}
return(ret);
}
int dinic(int s,int t)
{
int ans=0;
while(makelevel(s,t)) ans+=dfs(s,inf,t);
return(ans);
}
int main()
{
edgeini(maxn);
int m,n;
scanf("%d %d",&m,&n);
for(int i=1;i<=m;i++) scanf("%d",&a[i]);
int last[maxn];
memset(last,0,sizeof(last));
for(int i=1;i<=n;i++)
{
int tmp;
scanf("%d",&tmp);
int txt;
for(int j=1;j<=tmp;j++)
{
scanf("%d",&txt);
if(last[txt]==0)
{
edgemake(i,txt+n,inf);
}
else
{
edgemake(i,last[txt],inf);
}
last[txt]=i;
}
scanf("%d",&txt);
edgemake(0,i,txt);
}
for(int i=1;i<=m;i++)
edgemake(i+n,n+m+1,a[i]);
int ans=dinic(0,n+m+1);
printf("%d\n",ans);
return 0;
}