这道题的建图比较有趣,流入猪圈的和流入超级汇点的是常规的建法,然后根据题目性质,除了在猪圈和有相应钥匙的人之间连边,同时也在依次同一个猪圈买猪的人之间依次连边,因为这样可以保证上一个人打开的猪圈剩下的猪可以流向下一个人,对公共的猪圈而言,是剩下的猪流向下一个人。这样就符合题意了。
加当前弧优化的Dinic
&i居然是参变量可以让等于它的变量的值跟着改。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
using namespace std;
#define MAXN 110
#define MAXM 1010
#define INF 0x7fffffff
struct node{
int x,y,cap,next;
}edge[MAXN*MAXM*2];
int s,t,n,m,x,z,y,a,A,l;
int d[MAXN+MAXM];
bool vis[MAXN+MAXM];
int head[MAXN+MAXM],cur[MAXN+MAXM],last[MAXN+MAXM];
void add(int x,int y,int z)
{
l++;
edge[l].x=x;edge[l].y=y;edge[l].cap=z;
edge[l].next=head[x];head[x]=l;
}
bool BFS()
{
queue<int> q;
memset(d,0,sizeof(d));
d[s]=1;q.push(s);
memset(vis,0,sizeof(vis));
vis[s]=1;
while (!q.empty())
{
int x=q.front();q.pop();
for (int i=head[x];i!=-1;i=edge[i].next)
if (!vis[edge[i].y] && edge[i].cap>0)
{
q.push(edge[i].y);
vis[edge[i].y]=1;
d[edge[i].y]=d[x]+1;
}
}
return d[t]!=0;
}
int dfs(int x,int f)
{
if (x==t || f==0) return f;
int l=f,tmp;
for (int i=cur[x];i!=-1;i=edge[i].next)
if (d[edge[i].y]==d[x]+1 && edge[i].cap>0)
{
tmp=dfs(edge[i].y,min(edge[i].cap,l));
l-=tmp;
edge[i].cap-=tmp;
edge[i^1].cap+=tmp;
if (l==0) return f;
}
return f-l;
}
int Dinic(int s,int t)
{
int flow=0;
while (BFS())
{
for (int i=s;i<=t;i++) cur[i]=head[i];
flow+=dfs(s,INF);
}
return flow;
}
int main()
{
scanf("%d%d", &m, &n);
s=0;t=n+m+1;
memset(head,-1,sizeof(head));
l=-1;
for (int i=1;i<=m;i++)
{
scanf("%d", &z);
add(s,i,z);
add(i,s,0);
}
for (int i=1;i<=n;i++)
{
scanf("%d", &a);
for (int j=1;j<=a;j++)
{
scanf("%d", &A);
if (last[A]==0)
add(A,i+m,INF),add(i+m,A,0);
else
add(last[A],i+m,INF),add(i+m,last[A],0);
last[A]=i+m;
}
scanf("%d", &A);
add(i+m,t,A);
add(t,i+m,0);
}
printf("%d\n", Dinic(s,t));
}