POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)

参考网址:http://blog.csdn.net/acdreamers/article/details/16905653

树的重心的定义:

树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。

通常利用树形DP找重心:

BalanceAct: http://poj.org/problem?id=1655

题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的

清空的时候记得要清干净.....

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=20010;
 8 const int maxx=1<<30;
 9 int t,n;
10 int f[maxn]={};
11 int vis[maxn]={};
12 struct nod{
13     int y;
14     int next;
15 }e[2*maxn]={};
16 int head[maxn]={},tot=0;
17 int ans,size=0;
18 void init(int x,int y){
19     e[++tot].y=y;
20     e[tot].next=head[x];
21     head[x]=tot;
22 }
23 void dfs(int x){
24     int y;
25     vis[x]=1;
26     f[x]=0;
27     int tmp=0;
28     for(int i=head[x];i;i=e[i].next){
29         y=e[i].y;
30         if(!vis[y]){
31             dfs(y);
32             f[x]+=f[y]+1;
33             tmp=max(tmp,f[y]+1);
34         }
35     }tmp=max(tmp,n-f[x]-1);
36     if(tmp<size||(tmp==size&&x<ans)){
37         size=tmp;
38         ans=x;
39     }
40 }
41 void yu(){
42     size=maxx;
43     ans=maxx;
44     tot=0;
45     memset(f,0,sizeof(f));
46     memset(vis,0,sizeof(vis));
47     memset(head,0,sizeof(head));
48     memset(e,0,sizeof(e));
49 }
50 int main(){
51     scanf("%d",&t);
52     while(t-->0){
53         yu();
54         scanf("%d",&n);
55         int x,y;
56         for(int i=1;i<n;i++){
57             scanf("%d%d",&x,&y);
58             init(x,y);
59             init(y,x);
60         }
61         dfs(1);
62         printf("%d %d\n",ans,size);
63     }
64     return 0;
65 }

Godfather: http://poj.org/problem?id=3107

题意:给定一棵树,求树的所有重心,按照编号从小到大的顺序输出.

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=50010;
 8 const int maxx=1<<30;
 9 int t,n;
10 int f[maxn]={};
11 int vis[maxn]={};
12 struct nod{
13     int y;
14     int next;
15 }e[2*maxn]={};
16 int head[maxn]={},tot=0;
17 int ans[maxn]={},size=0,sum=0;
18 void init(int x,int y){
19     e[++tot].y=y;
20     e[tot].next=head[x];
21     head[x]=tot;
22 }
23 void dfs(int x){
24     int y;
25     vis[x]=1;
26     int tmp=0;
27     for(int i=head[x];i;i=e[i].next){
28         y=e[i].y;
29         if(!vis[y]){
30             dfs(y);
31             f[x]+=f[y]+1;
32             tmp=max(f[y]+1,tmp);
33         }
34     }
35     tmp=max(tmp,n-f[x]-1);
36     if(tmp<size){
37         size=tmp;
38         sum=0;
39         ans[++sum]=x;
40     }
41     else if(tmp==size){
42         ans[++sum]=x;
43     }
44 }
45 int main(){
46     size=maxx;
47     scanf("%d",&n);
48     int x,y;
49     for(int i=1;i<n;i++){
50         scanf("%d%d",&x,&y);
51         init(x,y);
52         init(y,x);
53     }
54     dfs(1);
55     sort(ans+1,ans+1+sum);
56     for(int i=1;i<sum;i++){
57         printf("%d ",ans[i]);
58     }
59     printf("%d\n",ans[sum]);
60     return 0;
61 }

时间: 2024-10-18 03:21:32

POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)的相关文章

POJ 1655 Balancing Act(求树的重心--树形DP)

题意:求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. 思路:随便选一个点把无根图转化成有根图,dfs一遍即可dp出答案 //1348K 125MS C++ 1127B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; int

POJ 3107 Godfather (树的重心)

题目地址:POJ 3107 还是裸的树的重心,只不过这个要求将所有的重心都输出.很简单. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include &

poj 1655 Balancing Act 【树的重心】

知识点:树的重心 定义:以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半. 性质: 性质 1 :树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样. 性质 2 :把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 性质 3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置. 题目:poj 1655 Balancing Act 题意:给出一颗树,求树的重心点以及重心点删除后中的最大子树.

poj 1655 Balancing Act 求树的重心【树形dp】

poj 1655 Balancing Act 题意:求树的重心且编号数最小 一棵树的重心是指一个结点u,去掉它后剩下的子树结点数最少. (图片来源: PatrickZhou 感谢博主) 看上面的图就好明白了,不仅要考虑当前结点子树的大小,也要"向上"考虑树的大小. 那么其它就dfs完成就行了,son[] 存以前结点为根的结点个数. 这是用邻接表写: 1 #include<iostream> 2 #include<cstdio> 3 #include<cst

POJ 1655 Balancing Act(树的重心)

Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14062   Accepted: 5937 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or m

POJ 1655 Balancing Act (树的重心,常规)

题意:求树的重心,若有多个重心,则输出编号较小者,及其子树中节点最多的数量. 思路: 树的重心:指的是一个点v,在删除点v后,其子树的节点数分别为:u1,u2....,设max(v)为其中的最大值,点v的max(v)是所有点里面最小的,称v为树的重心. 如何求任一重心?按树形来看,max(v)可以由其父亲贡献,也可以由其任一孩子贡献.孩子比较好解决,不就是深搜一遍,然后回溯时统计下数量就行了?而父亲的怎么办?可以知道,点v到其父亲这一叉就是n-sum(v)了,sum(v)指的是以v为根的子树的节

POJ 1655 Balancing Act(求树的重心)

题目大意: 就是要求树的重心,重心的定义就是删除这个点使得森林尽量平衡. 也可以让分治子树的时候使得每颗子树的数量在nlogn以内. 思路分析: son [x] 表示x的子树的数量  不包括自己. balance 表示最大的森林的节点数. 最后我们要让最大的balance 最小. balance = max (balance ,n - 1 - son[x]  , son[j] +1).. #include <cstdio> #include <iostream> #include

POJ 1655 Balancing Act[树的重心/树形dp]

Balancing Act 时限:1000ms Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree

POJ 1655 Balancing Act (树的重心)

题意:求树的重心裸题. 拓展:树的重心可以在树分治时避免退化链时的最坏时间复杂度,提高时间效率. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue&g