_bzoj1497 [NOI2006]最大获利【最大权闭合子图】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1497

保存最大流模版。

选一个用户群,就必须要选对应的两个中转站,这种关系类似“最大全闭合子图”的关系,因此构图,求最小割。

#include <cstdio>
#include <cstring>
#include <algorithm>

const int maxn = 5005, maxm = 50005, maxe = 400000;

int n, m, t1, t2, t3, S, T, ans;
int head[maxn + maxm], to[maxe], next[maxe], from[maxe], cap[maxe], flow[maxe], lb;
int d[maxn + maxm], que[maxn + maxm], head_, tail, h, num[maxn + maxm], p[maxn + maxm];

inline void ist(int aa, int ss, int ca) {
	to[lb] = ss;
	from[lb] = aa;
	next[lb] = head[aa];
	head[aa] = lb;
	cap[lb] = ca;
	++lb;
	
	to[lb] = aa;
	from[lb] = ss;
	next[lb] = head[ss];
	head[ss] = lb;
	cap[lb] = 0;
	++lb;
}
inline int lbl(int i) {
	int rt = T;
	for (int j = head[i]; j != -1; j = next[j]) {
		if (cap[j] > flow[j]) {
			rt = std::min(rt, d[to[j]]);
		}
	}
	return rt + 1;
}
inline int fnd(int i) {
	for (int j = head[i]; j != -1; j = next[j]) {
		if (d[i] == d[to[j]] + 1 && cap[j] > flow[j]) {
			return j;
		}
	}
	return -1;
}
inline int maxflow(void) {
	int rt = 0, delta;
	int i = S, j, x;
	while (d[S] <= T) {
		j = fnd(i);
		if (j != -1) {
			p[to[j]] = j;
			i = to[j];
			if (i == T) {
				delta = 2147483647;
				for (; i != S; i = from[p[i]]) {
					delta = std::min(delta, cap[p[i]] - flow[p[i]]);
				}
				for (i = T; i != S; i = from[p[i]]) {
					flow[p[i]] += delta;
					flow[p[i] ^ 1] -= delta;
				}
				rt += delta;
			}
		}
		else {
			x = lbl(i);
			if (--num[d[i]] == 0) {
				return rt;
			}
			++num[d[i] = x];
			if (i != S) {
				i = from[p[i]];
			}
		}
	}
	return rt;
}

int main(void) {
	//freopen("in.txt", "r", stdin);
	memset(head, -1, sizeof head);
	memset(next, -1, sizeof next);
	scanf("%d%d", &n, &m);
	T = n + m + 1;
	
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &t3);
		ist(S, i, t3);
	}
	for (int i = n + 1; i <= n + m; ++i) {
		scanf("%d%d%d", &t1, &t2, &t3);
		ans += t3;
		ist(i, T, t3);
		ist(t1, i, 0x3c3c3c3c);
		ist(t2, i, 0x3c3c3c3c);
	}
	
	memset(d, 0x3c, sizeof d);
	d[T] = 0;
	que[tail++] = T;
	while (head_ != tail) {
		h = que[head_++];
		++num[d[h]];
		for (int j = head[h]; j != -1; j = next[j]) {
			if ((j & 1) && d[to[j]] == 0x3c3c3c3c) {
				d[to[j]] = d[h] + 1;
				que[tail++] = to[j];
			}
		}
	}
	printf("%d\n", ans - maxflow());
	return 0;
}

  

posted @ 2016-12-15 14:06  ciao_sora  阅读(208)  评论(0编辑  收藏  举报