最大流:
新增源点0,汇点N+1
从源点发出m条边,每条边容量为猪圈m的存货,
然后m条边依次流经每个有对应猪圈钥匙的顾客,顾客之间连边为INF,
若不同猪圈流经同一个顾客,则边权相加。
这些边代表猪圈存货的限制。
从每个顾客发出一条边指向汇点,边权为顾客需求。
这些边代表顾客需求的限制。
此时,在这张图上最大流即可。
// ShellDawn
// POJ1149
// No.16
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define MM(x) memset(x,0,sizeof(x))
#define INF 0x3f3f3f3f
using namespace std;
#define maxn 105
#define maxm 1005
int n,m;
int pigs[maxm];
int cus[maxn];
// 邻接矩阵
int E[maxn][maxn];
// 邻接表
int P[maxm][maxn][2];
int C[maxm];
// END
int V[maxn];
void make_edge(){
MM(E);
for(int i=1;i<=m;i++){
if(C[i] > 0){
int a = P[i][0][0];
E[0][a] += pigs[i];
}
for(int j=1;j<C[i];j++){
int a = P[i][j-1][0];
int b = P[i][j][0];
E[a][b] = INF;
}
}
for(int i=1;i<=n;i++){
E[i][n+1] = cus[i];
}
}
bool BFS(int s){
MM(V);MM(C);
queue<int> q;
q.push(s);
V[s] = 1;
while(!q.empty()){
int loc = q.front();
q.pop();
for(int i=1;i<=n+1;i++){
if(V[i] == 0 && E[loc][i] > 0){
q.push(i);
V[i] = V[loc] + 1;
P[loc][C[loc]][0] = i;
P[loc][C[loc]][1] = E[loc][i];
C[loc]++;
if(i == n+1) return true;
}
}
}
return false;
}
int DFS(int now,int minflow){
if(now == n+1) return minflow;
int flow = 0;
for(int i=0;i<C[now];i++){
int next = P[now][i][0];
int v = P[now][i][1];
int f = DFS(next,min(minflow,v));
minflow -= f;
flow += f;
E[now][next] -= f;
E[next][now] += f;
}
return flow;
}
void Dinic(){
int maxflow = 0;
while(BFS(0)){
maxflow += DFS(0,INF);
}
cout<<maxflow<<endl;
}
int main(){
while(cin>>m>>n){
for(int i=1;i<=m;i++){
cin>>pigs[i];
}
MM(C);
for(int i=1;i<=n;i++){
int T;
cin>>T;
while(T--){
int a;
cin>>a;
P[a][C[a]++][0] = i;
}
cin>>cus[i];
}
make_edge();
Dinic();
}
return 0;
}