又是一个网络流的构图题。不是那么容易就想得到的,尤其是没有接触到很多网络流题目时。构图时由于人的数目较少,因此就只用人做结点。对于每一个猪舍的钥匙,若是第一次出现,则源点与该人连接一条边,容量为该猪舍的初始猪的数目,否则,当前人与前一个有此钥匙的人连一条边,容量无穷大。最后每一个人和汇点连一条边,容量为是他想买的猪的数目,最后,求一次最大流即可。
这里有个很详细的解题报告:
http://imlazy.ycool.com/post.2059102.html
以下是代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int M=10000;
const int N=1200;
const int INF=1<<29;
struct node
{
int u,v,cap,flow;
int next;
}edge[2*M];
int head[N],num;
int store[N],vis[N];
int level[N];
int m,n,s1,t1;
void init()
{
for(int i=0;i<=n+m+3;i++)
head[i]=-1;
num=0;
s1=0;t1=n+m+1;
}
void addege(int u,int v,int cap)
{
edge[num].u=u;
edge[num].v=v;
edge[num].cap=cap;
edge[num].flow=0;
edge[num].next=head[u];
head[u]=num++;
edge[num].u=v;
edge[num].v=u;
edge[num].cap=0;
edge[num].flow=0;
edge[num].next=head[v];
head[v]=num++;
}
int dinic_dfs(int sta,int end,int ver)
{
int stack[N*10],top=0;
int flow=0,cur,ptr,pre[N],minf,i;
int del[N];
for(i=0;i<=ver;i++)
{
del[i]=0;
}
stack[top++]=sta;
pre[sta]=sta;
cur=sta;
while(top)
{
while(cur!=end && top)
{
for(i=head[cur];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(level[v]==level[cur]+1 && edge[i].cap>edge[i].flow && !del[v])
{
stack[top++]=v;
cur=v;
pre[v]=i;
break;
}
}
if(i==-1)
{
del[cur]=1;
top--;
if(top)
cur=stack[top-1];
}
}
if(cur==end)
{
minf=INF;
while(cur!=sta)
{
cur=pre[cur];
if(edge[cur].cap-edge[cur].flow<minf) minf=edge[cur].cap-edge[cur].flow;
cur=edge[cur].u;
}
cur=end;
while(cur!=sta)
{
cur=pre[cur];
edge[cur].flow+=minf;
edge[cur^1].flow-=minf;
if(edge[cur].cap-edge[cur].flow==0)
{
ptr=edge[cur].u;
}
cur=edge[cur].u;
}
while(top>0 && stack[top-1]!=ptr) top--;
if(top) cur=stack[top-1];
flow+=minf;
}
}
return flow;
}
bool dinic_bfs(int sta,int end,int ver)
{
int i,j;
int queue[10*N];
for(i=0;i<=ver;i++)
{
level[i]=-1;
}
int rear=0;
queue[rear++]=sta;
level[sta]=0;
for(i=0;i<rear;i++)
{
for(j=head[queue[i]];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(level[v]==-1 && edge[j].cap>edge[j].flow)
{
level[v]=level[queue[i]]+1;
queue[rear++]=v;
}
}
}
return level[end]>=0;
}
int dinic(int sta,int end,int ver)
{
int flow=0,t;
while(dinic_bfs(sta,end,ver))
{
t=dinic_dfs(sta,end,ver);
if(t) flow+=t;
else break;
}
return flow;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&m,&n);
init();
int i,j;
int a,b,c;
memset(vis,0,sizeof(vis));
for(i=1;i<=m;i++)
scanf("%d",&store[i]);
for(i=1;i<=n;i++)
{
scanf("%d",&a);
for(j=0;j<a;j++)
{
scanf("%d",&b);
if(!vis[b])
{
addege(s1,i,store[b]);
}
else
addege(vis[b],i,INF);
vis[b]=i;
}
scanf("%d",&c);
addege(i,t1,c);
}
printf("%d/n",dinic(s1,t1,t1+1));
return 0;
}