POJ 1655 Balancing Act【树的重心】
Balancing Act
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 14251 | Accepted: 6027 |
Description
For example, consider the tree:
Deleting node 4 yields two trees whose member nodes are {5} and {1,2,3,6,7}. The larger of these two trees has five nodes, thus the balance of node 4 is five. Deleting node 1 yields a forest of three trees of equal size: {2,6}, {3,7}, and {4,5}. Each of these trees has two nodes, so the balance of node 1 is two.
For each input tree, calculate the node that has the minimum balance. If multiple nodes have equal balance, output the one with the lowest number.
Input
Output
Sample Input
1 7 2 6 1 2 1 4 4 5 3 7 3 1
Sample Output
1 2
Source
题目很好理解,就是去掉树上的一个节点,看看剩下的子树中最大的是多少,然后在这些最大值中求一个最小值,如果有多个点都是最小值,那么找一个序号最小的节点。输出节点号,和最小值。
经过简单分析,DFS深度优先搜索可以解决,只需要求出每个节点下子树的总结点个数即可。
这题其实是求重心的裸题!
举例说明:
设有一棵树20个节点,其中有一个节点为u,u有两个孩子节点,设u以下有10个节点,两个孩子分别有6和4个节点,那么对于u来说,最大是多少,应该是20 - 10,6,4中的最大的也就是10.这样等把所有节点的最大值求出后,再求1-n中的最小值,输出该点以及最小值即可。
算法就是DFS,计算出每个节点下的总数,然后保留本节点下的孩子节点子树中的最大值,然后和自己的祖先节点比较求出最大值,最后枚举最小值。
这题一定要建一个双向图,因为树是无向的。
下面是AC代码:
1 #include <stdio.h> 2 #include <string.h> 3 #define max(a,b) (a)>(b)?(a):(b) 4 const int maxn=20010; 5 struct Edge//前向星存边 6 { 7 int to,next; 8 }edge[maxn<<1];//保存双向图 9 int head[maxn],tot; 10 inline void init()//初始化操作 11 { 12 memset(head,-1,sizeof(head)); 13 tot=0; 14 } 15 inline void addedge(int u,int v)//加边 16 { 17 edge[tot].to=v; 18 edge[tot].next=head[u]; 19 head[u]=tot++; 20 } 21 int dp[maxn];//每个节点去掉后其他子树的点数 22 int num[maxn];//每个节点下的节点总数 23 int n; 24 inline void DFS(int u,int pre) 25 { 26 dp[u]=0;//初始化 27 num[u]=1;//初始化 28 for(int i=head[u];i!=-1;i=edge[i].next) 29 { 30 int v=edge[i].to; 31 if(v==pre) 32 continue; 33 DFS(v,u); 34 dp[u]=max(dp[u],num[v]);//求根节点下儿子节点中的最大值 35 num[u]+=num[v];//求根节点下的所有节点数 36 } 37 dp[u]=max(dp[u],n-num[u]);//祖先节点总数的最大值和根节点下儿子节点中的最大值作为本节点的最大值 38 } 39 int main() 40 { 41 int T; 42 scanf("%d",&T); 43 int u,v; 44 while(T--) 45 { 46 scanf("%d",&n); 47 init(); 48 for(int i=1;i<n;i++)//建图 49 { 50 scanf("%d%d",&u,&v); 51 addedge(u,v); 52 addedge(v,u); 53 } 54 DFS(1,-1); 55 int ans1=1,ans2=dp[1]; 56 for(int i=2;i<=n;i++)//求最小值 57 { 58 if(ans2>dp[i]) 59 { 60 ans1=i; 61 ans2=dp[i]; 62 } 63 } 64 printf("%d %d\n",ans1,ans2); 65 } 66 return 0; 67 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。