day23T1改错记

题目描述

两颗点集相同的树(点编号\(1\)~\(n\)),每个点有一个权值\(a_i\),你要选出一个点集的子集,这个点集的点在两棵树上都是一个联通块,求选出的点集的权值和最大值

多组数据,数据组数为\(T\)

\(T \le 50, n \le 100, |a_i| \le 1000\)

解析

直接考虑联通块不方便,不妨枚举某个点一定被选的情况

枚举必选点\(i\),那么如果选了另外的某个点\(j\)\(i\)\(j\)路径上的点也要选

\(i\)置为树根,那么如果选\(j\)\(j\)在两棵树上的父亲也要选

于是把每个点\(j\)向两个父亲连边,问题变成了最大权闭合子图

多组数据\(O(T)\),枚举树根\(O(n)\),最大流\(O(n^2m) = O(n^2 \cdot 3n) = O(n^3)\)

所以总复杂度\(O(Tn^4)\),怎么看都过不了但是实际上跑得还不慢???

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 105

typedef long long LL;
const int inf = 0x3f3f3f3f;
struct Graph {
	struct Edge {
		int v, next, cap;
		Edge(int _v = 0, int _n = 0, int _c = 0):v(_v), next(_n), cap(_c) {}
	} edge[MAXN << 4];
	int head[MAXN << 1], cur[MAXN << 1], cnt, dep[MAXN << 1];
	void init() { memset(head, -1, sizeof head); cnt = 0; }
	void add_edge(int u, int v, int c) { edge[cnt] = Edge(v, head[u], c); head[u] = cnt++; }
	void insert(int u, int v, int c) { add_edge(u, v, c); add_edge(v, u, 0); }
	bool bfs();
	int dfs(int, int);
	int dinic();
};
struct Tree {
	struct Edge {
		int v, next;
		Edge(int _v = 0, int _n = 0):v(_v), next(_n) {}
	} edge[MAXN << 1];
	int head[MAXN], fa[MAXN], cnt;
	void init() { memset(head, -1, sizeof head); cnt = 0; }
	void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; }
	void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }
	void dfs(int, int);
};

void build(int, int);

Graph G;
Tree t1, t2;
int N, T, val[MAXN], ans, sum;

int main() {
	scanf("%d", &T);
	while (T--) {
		t1.init(), t2.init();
		ans = sum = 0;
		scanf("%d", &N);
		for (int i = 1; i <= N; ++i) {
			scanf("%d", val + i);
			if (val[i] > 0) sum += val[i];
		}
		for (int i = 1; i < N; ++i) {
			int u, v; scanf("%d%d", &u, &v);
			t1.insert(u, v);
		}
		for (int i = 1; i < N; ++i) {
			int u, v; scanf("%d%d", &u, &v);
			t2.insert(u, v);
		}
		for (int i = 1; i <= N; ++i) {
			G.init();
			t1.dfs(i, 0), t2.dfs(i, 0);
			for (int j = 1; j <= N; ++j) {
				if (j ^ i) G.insert(j, t1.fa[j], inf), G.insert(j, t2.fa[j], inf);
				if (val[j] > 0) G.insert(0, j, val[j]);
				else G.insert(j, N + 1, -val[j]);
			}
			ans = std::max(ans, sum - G.dinic());
		}
		printf("%d\n", ans);
	}

	return 0;
}
bool Graph::bfs() {
	memset(dep, 0, sizeof dep);
	static int que[MAXN << 1], hd, tl;
	hd = tl = 0;
	que[tl++] = 0, dep[0] = 1;
	while (hd < tl) {
		int p = que[hd++];
		if (p == N + 1) break;
		for (int i = head[p]; ~i; i = edge[i].next)
			if (edge[i].cap && !dep[edge[i].v]) {
				dep[edge[i].v] = dep[p] + 1;
				que[tl++] = edge[i].v;
			}
	}
	return dep[N + 1];
}
int Graph::dfs(int u, int maxflow) {
	if (u == N + 1) return maxflow;
	int res = 0;
	for (int &i = cur[u]; ~i; i = edge[i].next)
		if (edge[i].cap && dep[edge[i].v] == dep[u] + 1) {
			int d = dfs(edge[i].v, std::min(maxflow, edge[i].cap));
			if (d) {
				edge[i].cap -= d, edge[i ^ 1].cap += d;
				res += d, maxflow -= d;
				if (!maxflow) break;
			}
		}
	if (!res) dep[u] = -1;
	return res;
}
int Graph::dinic() {
	int res = 0;
	while (bfs()) {
		memcpy(cur, head, sizeof head);
		res += dfs(0, inf);
	}
	return res;
}
void Tree::dfs(int u, int f) {
	fa[u] = f;
	for (int i = head[u]; ~i; i = edge[i].next)
		if (edge[i].v ^ f) dfs(edge[i].v, u);
}
//Rhein_E 100pts
posted @ 2019-03-26 16:50  Rhein_E  阅读(137)  评论(0编辑  收藏  举报