AT4995 [AGC034E] Complete Compress

https://www.luogu.com.cn/problem/AT4995

枚举最后移动到的那个点,然后考虑DP
设 f [ u ] f[u] f[u]表示以 u u u结点为子树尽量多匹配点的移动的距离和(把多少对移动到)

草讲不清楚,看代码吧

code:

#include<bits/stdc++.h>
#define N 2005
using namespace std;
int dis[N], siz[N], a[N], n, f[N], ans;
vector<int> g[N];
void dfs(int u, int fa) {
    dis[u] = 0, siz[u] = a[u];
    int p = 0;
    for(int v : g[u]) {
        if(v == fa) continue;
        dfs(v, u); siz[u] += siz[v], dis[u] += dis[v];
        if(dis[v] > dis[p]) p = v;
    }
    int sum = dis[u], ma = dis[p];
    if(!p) f[u] = 0;
    else if(sum - ma >= ma) f[u] = dis[u] / 2;
    else f[u] = sum - ma + min((sum - 2 * (sum - ma)) / 2, f[p]);
    if(fa) dis[u] += siz[u];
}
void solve(int u) {
    dfs(u, 0);
    // printf("   %d %d   %d\n", u, dis[u], f[u]);
    // for(int i = 1; i <= n; i ++) printf("%d ", dis[i]); printf("\n");
    // for(int i = 1; i <= n; i ++) printf("%d ", siz[i]); printf("\n");
    // for(int i = 1; i <= n; i ++) printf("%d ", f[i]); printf("\n");
    if(dis[u] % 2 == 0 && f[u] * 2 == dis[u]) ans = min(ans, f[u]);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%1d", &a[i]);
    for(int i = 1; i < n; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v), g[v].push_back(u);
    }
    ans = 1e9;
    for(int i = 1; i <= n; i ++) solve(i);
    if(ans == (int)1e9) ans = -1;
    printf("%d", ans);
    return 0;
}
上一篇:学习笔记:树上启发式合并(dsu on tree)


下一篇:windows下安装virtualenvwrapper