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

转载于:https://www.cnblogs.com/Rhein-E/p/10601243.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值