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