首页 > 代码库 > 树形DP求树的重心 --SGU 134
树形DP求树的重心 --SGU 134
令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值。
则树的重心定义为:一个点,这个点的属性值在所有点中是最小的。
SGU 134 即要找出所有的重心,并且找出重心的属性值。
考虑用树形DP。
dp[u]表示割去u点,得到的连通分支的节点数的最大值。
tot[u]记录以u为根的这棵子树的节点数总和(包括根)。
则用一次dfs即可预处理出这两个数组。再枚举每个点,每个点的属性值其实为max(dp[u],n-tot[u]),因为有可能最大的连通分支在u的父亲及以上。然后记录答案就可以了。
代码:
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <vector>using namespace std;vector<int> G[16005];int dp[16005],tot[16005];vector<int> ans;void dfs(int u){ tot[u] = 1; for(int i=0;i<G[u].size();i++) { int v = G[u][i]; if(tot[v] == -1) dfs(v); else continue; dp[u] = max(dp[u],tot[v]); tot[u] += tot[v]; }}int main(){ int n,i,j,u,v; scanf("%d",&n); for(i=0;i<=n;i++) G[i].clear(); for(i=0;i<n-1;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } memset(dp,0,sizeof(dp)); memset(tot,-1,sizeof(tot)); dfs(1); int mini = Mod; for(i=1;i<=n;i++) { int tmp = max(dp[i],n-tot[i]); if(tmp < mini) { ans.clear(); ans.push_back(i); mini = tmp; } else if(tmp == mini) ans.push_back(i); } printf("%d %d\n",mini,ans.size()); sort(ans.begin(),ans.end()); printf("%d",ans[0]); for(i=1;i<ans.size();i++) printf(" %d",ans[i]); puts(""); return 0;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。