首先考虑猪无法流动,那么源点向每一个猪圈连猪圈中猪个数的边,每一个顾客向汇点连所需猪的边,每一个猪圈向能打开它的顾客连inf的边,跑最大流即可。
但考虑猪要流动,有一个十分巧妙地做法,将每一个顾客所有有公共猪圈的顾客连inf的边,同时每一个猪圈只连向第一次打开它的顾客(也可以流向所有顾客,不过没必要),这样就可以解决了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2001 4 #define inf 0x3f3f3f3f 5 struct ji{ 6 int nex,to,len; 7 }edge[N*20]; 8 queue<int>q; 9 int E,n,m,p,k,id[N],d[N],head[N],work[N]; 10 void add(int x,int y,int z){ 11 edge[E].nex=head[x]; 12 edge[E].to=y; 13 edge[E].len=z; 14 head[x]=E++; 15 if (E&1)add(y,x,0); 16 } 17 bool bfs(){ 18 q.push(0); 19 memset(d,-1,sizeof(d)); 20 d[0]=0; 21 while (!q.empty()){ 22 int k=q.front(); 23 q.pop(); 24 for(int i=head[k];i!=-1;i=edge[i].nex) 25 if ((edge[i].len)&&(d[edge[i].to]<0)){ 26 d[edge[i].to]=d[k]+1; 27 q.push(edge[i].to); 28 } 29 } 30 return d[n]>=0; 31 } 32 int dfs(int k,int s){ 33 if (k==n)return s; 34 int p; 35 for(int &i=work[k];i!=-1;i=edge[i].nex) 36 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 37 p=dfs(edge[i].to,min(s,edge[i].len)); 38 if (p){ 39 edge[i].len-=p; 40 edge[i^1].len+=p; 41 return p; 42 } 43 } 44 return 0; 45 } 46 int dinic(){ 47 int k,ans=0; 48 while (bfs()){ 49 memcpy(work,head,sizeof(work)); 50 while (k=dfs(0,inf))ans+=k; 51 } 52 return ans; 53 } 54 int main(){ 55 scanf("%d%d",&m,&n); 56 memset(head,-1,sizeof(head)); 57 for(int i=1;i<=m;i++){ 58 scanf("%d",&p); 59 add(0,i,p); 60 id[i]=i; 61 } 62 for(int i=1;i<=n;i++){ 63 scanf("%d",&k); 64 for(int j=1;j<=k;j++){ 65 scanf("%d",&p); 66 add(id[p],m+i,inf); 67 id[p]=m+i; 68 } 69 scanf("%d",&p); 70 add(m+i,n+m+1,p); 71 } 72 n+=m+1; 73 printf("%d",dinic()); 74 }