树形DP-求树的重心Balancing Act POJ - 1655
首先要了解树的重心的含义是什么?
树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
这道题是求把某个的节点和删去后,生成是剩下的树中最大子树节点最少是是多少个?
并输出节点。
我们可以利用DSF+DP求解。
首先,我们想如何求子树节点的个数?这个其实是比较简单的。
任选一个节点作为根节点。DFS的时候,我们每次深搜后保存相应节点的个数,当DFS
那么DFS后,我们知道当前的DFS是已经解决的(递归),那么我们保存每次DFS后,就知道已经DFS前面那个节点的子节点个数,所以我能知道,当前节点的儿子节点个数。那么在每个儿子节点个数中取最大值,再与剩下节点的值比较,由于我们知道剩下的节点,就是这个节点的祖先节点个数所以我们只需要把,N-当前节点的子节点-1,就是这个节点的祖先节点个数,再和每个儿子节点个数取大者即可。
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> using namespace std; const int maxx = 200000+5; vector<int>G[maxx]; int d[maxx];//保存的是当前节点的儿子节点数目 int vis[maxx]; int sum,num,n; void dfs(int x) { vis[x]=1; int num_son=1; for (int i=0; i<G[x].size(); i++) { int now=G[x][i];//当前访问的节点 if(!vis[now]) //如果没有访问 { dfs(now);//DFS d[x]+=(d[now]+1);//D[now]保存的是now的儿子节点个数,+1就是当前节点的儿子节点个数 num_son=max(d[now]+1,num_son);//取大的 } } num_son=max(num_son,n-d[x]-1); if (num_son<sum || (num_son==sum && x<num))//维护 { sum=num_son; num=x; } return ; } int main() { int t,u,v; scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); for (int i=1; i<=n; i++) { G[i].clear(); } memset(vis,0,sizeof(vis)); scanf("%d",&n); sum=n; num=1; for (int i=1; i<n; i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1); printf("%d %d\n",num,sum); } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)

浙公网安备 33010602011771号