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;
}