[BZOJ1280][POJ1149]Emmy卖猪pigs

[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;
}
posted @ 2017-11-27 21:29  xjr01  阅读(266)  评论(0编辑  收藏  举报