/*
translation:
有M个猪圈,每个猪圈里初始时有若干头猪。一开始所有猪圈都是关闭的。依次来了N个顾客,
每个顾客分别会打开指定的几个猪圈,从中买若干头猪。每个顾客分别都有他能够买的数量
的上限。每个顾客走后,他打开的那些猪圈中的猪,都可以被任意地调换到其它开着的猪圈里,
然后所有猪圈重新关上。问总共最多能卖出多少头猪。(1 <= N <= 100, 1 <= M <= 1000)
solution:
最大流
paper题,论文“网络流建模汇总”里面有详细描述建模过程。
note: *
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1100 + 50;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, cap, rev;
Edge(int to_, int cap_, int rev_):to(to_),cap(cap_),rev(rev_){}
};
vector<Edge> G[maxn];
int level[maxn], iter[maxn];
int m, n, pigs[maxn]; //m pig-houses, n customers
bool linked[maxn][maxn];
void add_edge(int from, int to, int cap)
{
//printf("from %d to %d, cap = %d\n", from, to, cap);
G[from].push_back(Edge(to, cap, G[to].size()));
G[to].push_back(Edge(from, 0, G[from].size()-1));
}
void bfs(int s)
{
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while(!que.empty()) {
int v = que.front(); que.pop();
for(int i = 0; i < G[v].size(); i++) {
Edge& e = G[v][i];
if(e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}
int dfs(int v, int t, int f)
{
if(v == t) return f;
for(int& i = iter[v]; i < G[v].size(); i++) {
Edge& e = G[v][i];
if(e.cap > 0 && level[e.to] > level[v]) {
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int dinic(int s, int t)
{
int flow = 0;
for(;;) {
bfs(s);
if(level[t] < 0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f = dfs(s, t, INF)) > 0) flow += f;
}
}
void link_customer(const vector<int>& pig_house)
{
//sort(pig_house.begin(), pig_house.end());
int len = pig_house.size();
for(int i = 0; i < len-1; i++) {
int u = pig_house[i], v = pig_house[i+1];
if(!linked[u][v]) {
add_edge(u, v, INF);
linked[u][v] = true;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d", &m, &n)) { //m pig-houses, n customers
for(int i = 0; i < maxn; i++) G[i].clear();
memset(linked, 0, sizeof(linked)); //linked[i][j]:=顾客i以及顾客j已经相连
for(int i = 0; i < m; i++) scanf("%d", &pigs[i]);
int num, tmp, s = n, t = s + 1;
vector<int> pig_house[maxn];
for(int i = 0; i < n; i++) {
scanf("%d", &num);
for(int j = 0; j < num; j++) {
scanf("%d", &tmp);
pig_house[tmp-1].push_back(i);
}
scanf("%d", &tmp);
add_edge(i, t, tmp);
}
for(int i = 0; i < m; i++) {
int u = pig_house[i][0];
add_edge(s, u, pigs[i]);
}
for(int i = 0; i < m; i++)
link_customer(pig_house[i]);
printf("%d\n", dinic(s, t));
}
return 0;
}