Loading

「刷题记录」POJ 1149 PIGS 猪

题目传送门:POJ 1149
网络流的好题
建图:因为有 \(n\) 个顾客,所以一共会进行 \(n\) 次交易,在每次交易中,没上锁的猪舍之间的猪可以相互转移,而我们为了让下一个顾客买到尽可能多的猪,可以把猪集中到下一个顾客与当前顾客都可以打开的猪舍里,建立一个超级汇点,连接所有的顾客,流量为顾客的需量,而在可以互相交换猪的的猪舍之间,也连边,流量为正无穷,顾客与其对应的猪舍之间也连边,流量为猪舍中猪的数量,建立一个超级源点,流量也为猪舍中猪的数量,大概图示如下
image
这里,我们发现,有些路径源点相同,到达的顾客也相同,我们可以将这些边进行合并,同时我们发现,对于第一次打开 \(i\) 号猪舍的顾客,在他之前 \(i\) 号猪舍的猪没有进行转移,所以这些猪舍连向该顾客的边的流量就是该猪舍的数量,我们可以将图进行压缩,如下
image
简洁多了
我们根据这个建图,跑最大流算法就行了
上代码:

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 110;
const int M = 1100;
const int E = 1e6 + 5;
const ll inf = 1e18;

int n, m, S, T, cnt;
ll maxflow;
int h[N], cur[N], pre[M], dep[N], inque[N];
ll a[M];
queue<int> q;

struct edge {
	int v, nxt;
	ll w;
} e[E];

void add(int u, int v, ll w) {
	e[++ cnt].v = v;
	e[cnt].w = w;
	e[cnt].nxt = h[u];
	h[u] = cnt;
}

int bfs() {
	for (int i = 0; i <= T; ++ i) {
		dep[i] = 1e9;
		inque[i] = 0;
		cur[i] = h[i];
	}
	while (!q.empty()) {
		q.pop();
	}
	q.push(S);
	inque[S] = 1, dep[S] = 0;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		inque[u] = 0;
		for (int i = h[u]; i; i = e[i].nxt) {
			int v = e[i].v;
			if (dep[v] > dep[u] + 1 && e[i].w) {
				dep[v] = dep[u] + 1;
				if (!inque[v]) {
					q.push(v);
					inque[v] = 1;
				}
				if (v == T)	return 1;
			}
		}
	}
	return 0;
}

ll dfs(int u, ll flow) {
	if (u == T) {
		maxflow += flow;
		return flow;
	}
	ll used = 0, rlow = 0;
	for (int i = cur[u]; i; i = e[i].nxt) {
		cur[u] = i;
		int v = e[i].v;
		if (e[i].w && dep[v] == dep[u] + 1) {
			rlow = dfs(v, min(flow - used, e[i].w));
			if (rlow) {
				e[i].w -= rlow;
				e[i ^ 1].w += rlow;
				used += rlow;
				if (used == flow)	break;
			}
		}
	}
	return used;
}

int main() {
	m = read(), n = read();
	for (int i = 1; i <= m; ++ i) {
		a[i] = read();
	}
	T = n + 1;
	cnt = 1;
	for (int i = 1; i <= n; ++ i) {
		int k = read(), u;
		ll y = 0;
		for (int j = 1; j <= k; ++ j) {
			int x = read();
			if (pre[x] == 0) {
				y += a[x];
			}
			else {
				add(pre[x], i, inf);
				add(i, pre[x], 0);
			}
			pre[x] = i;
		}
		add(S, i, y);
		add(i, S, 0);
		u = read();
		add(i, T, u);
		add(T, i, 0);
	}
	while (bfs()) {
		dfs(S, inf);
	}
	printf("%lld\n", maxflow);
	return 0;
}
posted @ 2023-01-05 17:48  yi_fan0305  阅读(44)  评论(0编辑  收藏  举报