[BZOJ1280][POJ1149]Emmy卖猪pigs
试题描述
Emmy在一个养猪场工作。这个养猪场有 \(M\) 个锁着的猪圈,但Emmy并没有钥匙。顾客会到养猪场来买猪,一个接着一个。每一位顾客都会有一些猪圈的钥匙,他们会将这些猪圈打开并买走固定数目的猪。 所有顾客有的钥匙和他们需要买猪的数量在事先都告诉了Emmy,于是Emmy要订一个计划,使得卖出去的猪最多。 买卖的过程是这样的:一个顾客前来,并打开所有他可以打开的猪圈。然后Emmy从这些猪圈里牵出固定数目的猪卖给顾客(最多只能和顾客需要数相等),并可以重新安排这些开着的猪圈中的猪。 每个猪圈可以存放任意数目的猪。 写一个程序,使得Emmy能够卖出去尽可能多的猪。
输入
第一行有两个整数:\(M\) 和 \(N\),表示猪圈数和顾客数。 第二行有 \(M\) 个整数,表示每个猪圈初始时有多少猪。 接下来的 \(N\) 行按照前来的次序描述了每一个顾客,每行的格式如下:\(A\ K_1\ K_2 \cdots K_A\ B\) \(A\) 表示该顾客拥有的钥匙数,\(K_1 \cdots K_A\) 表示每个钥匙所对应的猪圈,\(B\) 表示该顾客需要购买的猪的数目。
输出
仅包含一个整数,即最多能卖出去的猪的数目。
输入示例
3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6
输出示例
7
数据规模及约定
\(1 \le M \le 1000\)
\(1 \le N \le 100\)
题解
首先源点向每个猪圈连一条容量为该猪圈内猪数目的边,然后每位客户向汇点连一条容量为该客户需要数的边。这是显然的。
那么根据“可以打乱”这个性质,我们可以直接在客户和客户之间连边,而不是把边连回猪圈。
这样,正解就产生了(以下边容量均为无穷):从猪圈向第一个有它钥匙的客户连边,然后有交集的客户之间连上边。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 1111
#define maxm 24010
#define oo 2147483647
struct Edge {
int from, to, flow;
Edge() {}
Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
};
struct Dinic {
int n, m, s, t, head[maxn], nxt[maxm];
Edge es[maxm];
int vis[maxn], Q[maxn], hd, tl;
int cur[maxn];
void init() {
m = 0; memset(head, -1, sizeof(head));
return ;
}
void setn(int _) {
n = _;
return ;
}
void AddEdge(int a, int b, int c) {
es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
return ;
}
bool BFS() {
memset(vis, 0, sizeof(vis));
vis[t] = 1;
hd = tl = 0; Q[++tl] = t;
while(hd < tl) {
int u = Q[++hd];
for(int i = head[u]; i != -1; i = nxt[i]) {
Edge& e = es[i^1];
if(!vis[e.from] && e.flow) {
vis[e.from] = vis[u] + 1;
Q[++tl] = e.from;
}
}
}
return vis[s] > 0;
}
int DFS(int u, int a) {
if(u == t || !a) return a;
int flow = 0, f;
for(int& i = cur[u]; i != -1; i = nxt[i]) {
Edge& e = es[i];
if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
flow += f; a -= f;
e.flow -= f; es[i^1].flow += f;
if(!a) return flow;
}
}
return flow;
}
int MaxFlow(int _s, int _t) {
s = _s; t = _t;
int flow = 0;
while(BFS()) {
rep(i, 1, n) cur[i] = head[i];
flow += DFS(s, oo);
}
return flow;
}
} sol;
#define maxpig 1010
#define maxcus 110
int n, p, A[maxpig];
vector <int> customer[maxpig];
bool G[maxcus][maxcus];
int main() {
n = read(); p = read(); int S = n + p + 1, T = n + p + 2;
sol.init(); sol.setn(T);
rep(i, 1, n) sol.AddEdge(S, i, read());
rep(i, 1, p) {
int k = read();
while(k--) customer[read()].push_back(i);
sol.AddEdge(i + n, T, read());
}
rep(i, 1, n) if(customer[i].size()) {
sol.AddEdge(i, customer[i][0] + n, oo);
rep(j, 1, (int)customer[i].size() - 1) {
int a = customer[i][j-1], b = customer[i][j];
if(!G[a][b]) sol.AddEdge(a + n, b + n, oo), G[a][b] = 1;
}
}
printf("%d\n", sol.MaxFlow(S, T));
return 0;
}