E32 树形DP 树的重心
如果删除树中某个节点,使得各个子树的最大节点数最小,则该节点被称为树的重心。
- 树的重心如果不唯一,则至多有 2 个,且这两个重心相邻。
- 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。
- 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。
- 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。
- 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。
// 树的重心 树形DP O(n) #include<bits/stdc++.h> using namespace std; const int N=50010; int n,siz[N],f[N],cnt=1e9; vector<int> e[N],g; void dfs(int u,int fa){ siz[u]=1; for(auto v:e[u]){ if(v==fa) continue; dfs(v,u); f[u]=max(f[u],siz[v]); //u的最大子树 siz[u]+=siz[v]; } f[u]=max(f[u],n-siz[u]); //删除u后的最大连通块 cnt=min(cnt,f[u]); //最大块最小化 } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } dfs(1,0); for(int i=1;i<=n;i++) if(f[i]==cnt) g.push_back(i); for(int v:g) printf("%d ",v); }
// 树的重心 树形DP O(n) #include<bits/stdc++.h> using namespace std; const int N=50010; int n,siz[N],f[N],d[N],cnt=1e9,v,sum; vector<int> e[N]; void dfs(int u,int fa){ siz[u]=1; for(auto v:e[u]){ if(v==fa) continue; dfs(v,u); f[u]=max(f[u],siz[v]); //u的最大子树 siz[u]+=siz[v]; } f[u]=max(f[u],n-siz[u]); //删除u后的最大连通块 cnt=min(cnt,f[u]); //最大块最小化 } void dfs2(int u,int fa){ for(auto v:e[u]){ if(v==fa) continue; d[v]=d[u]+1; dfs2(v,u); } sum+=d[u]; } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } dfs(1,0); for(int i=1;i<=n;i++) if(f[i]==cnt){v=i;break;} dfs2(v,0); printf("%d %d",v,sum); }
P12007 【MX-X10-T3】[LSOT-4] 全国联赛? - 洛谷
1655 -- Balancing Act (poj.org)
浙公网安备 33010602011771号