题意: 给定一个点的树,求以其中哪个点为根时可使得所有点的深度最小。
题解: 表示以
为根的所有结点深度和。那么
即答案。
具体实现:初始可以随便指定一个点为根,然后求出以
为根的所有点的深度,
,然后遍历其所有的子结点,求出以子结点为根的深度和来更新最小深度,一次
即可。求以子结点为根的深度和即将子结点拉成根,那么其子树的深度必定都减
,非子树部分的深度必定都加
。
注意避坑:不能直接将一个结点拉成根结点,必须在其父结点
为根的树的基础上,将
拉为根时,才符合
为
。
是
的子树深度都减
,
是非
的子树深度都加
。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, M = N << 1;
int n, f[N];
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dep[N], siz[N];
void dfs1(int u, int fa) {
siz[u] = 1;
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(v == fa) continue;
dep[v] = dep[u] + 1;
dfs1(v, u);
siz[u] += siz[v];
}
}
void dfs2(int u, int fa) {
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(v == fa) continue;
f[v] = f[u] - siz[v] + (n - siz[v]);
dfs2(v, u);
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d", &n);
for(int i = 1; i < n; i++) {
int a, b; scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
dfs1(1, 0);
for(int i = 1; i <= n; i++) f[1] += dep[i];
dfs2(1, 0);
int res = f[1];
for(int i = 2; i <= n; i++) res = min(res, f[i]);
printf("%d\n", res);
return 0;
}
京公网安备 11010502036488号