题意: 给定一个点的树,求以其中哪个点为根时可使得所有点的深度最小。
题解: 表示以
为根的所有结点深度和。那么
即答案。
具体实现:初始可以随便指定一个点为根,然后求出以
为根的所有点的深度,
,然后遍历其所有的子结点,求出以子结点为根的深度和来更新最小深度,一次
即可。求以子结点为根的深度和即将子结点拉成根,那么其子树的深度必定都减
,非子树部分的深度必定都加
。
注意避坑:不能直接将一个结点拉成根结点,必须在其父结点
为根的树的基础上,将
拉为根时,才符合
为
。
是
的子树深度都减
,
是非
的子树深度都加
。
代码:
#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; }