Loading

看完题目,我很熟练的建立了一个这样的毒瘤图

于是我快乐的 AC 了它。

int main() {
	scanf("%d%d", &m, &n);
	memset(head, -1, sizeof head);
	rep(i, 1, m) { scanf("%d", &s); addEdge(0, i, s); }

	s = 0, t = n * (m + 1) + 1;

	rep(i, 1, n) {
		int a, x;
		scanf("%d", &a);
		int base = (m + 1) * (i - 1);
		int r = (m + 1) * i;
		rep(j, 1, a) {
			scanf("%d", &x);
			addEdge(base + x, r, inf);
			addEdge(r, base + x, inf);
		}
		scanf("%d", &x); addEdge(r, t, x);
		if (i < n) {
			rep(j, 1, m)addEdge(base + j, base + j + m + 1, inf);
		}
	}
	printf("%d\n", Dinic());
}

但是,我眉头一皱,发现事情并不简单

\(5700ms\) ...

算了一下,大概有 \(n*(m+1)+1\) 这么多个点, \(1e5\) ... 边开了 \(1e6\) 才过

虽然说复杂度很宽松 , \(O(n^2m)\) ..

于是我看了一眼题解, 只有 \(n\) 个点

“在面对网络流问题时,如果一时想不出很好的构图方法,不如先构造一个最直观,或者说最“硬来”的模型,然后再用合并节点和边的方法来简直化这个模型。经过简化以后,好的构图思路自然就会涌现出来了。这是解决网络流问题的一个好方法。”

很显然我这个就是最原始的。

实际上这个图是可以合并的

可以把每一层的 $m + 1 $ 个点进行合并成一个点,记录下每个🐖圈之前的属主。

int main() {
	scanf("%d%d", &m, &n);
	memset(head, -1, sizeof head);
	rep(i, 1, m) scanf("%d", w + i);

	s = 0, t = n + 1;

	rep(i, 1, n) {
		int a, x;
		scanf("%d", &a);
		rep(j, 1, a) {
			scanf("%d", &x);
			if(!belong[x])addEdge(s,i,w[x]);
                        else addEdge(belong[x],i,inf);
                        belong[x] = i;
		}
		scanf("%d", &x); addEdge(i,t,x);
	}
	printf("%d\n", Dinic());
}

OJBK

真是美妙的建图(bushi

posted @ 2020-10-22 15:29  —O0oO-  阅读(103)  评论(0编辑  收藏  举报