POJ 1655 +POJ 3107【求树的重心】
2017-11-07 09:40
337 查看
树的重心:树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
eg:
删除1:子树1:2、6 子树2:4、5 子树3:3、7 ans[1]=2;
删除2:子树1:6 子树2:1、3、4、5、7 ans[2]=5;
删除3:子树1:7 子树2:1、2、4、5、6 ans[3]=5;
删除4:子树1:5 子树2:1、2、3、6、7 ans[4]=5;
删除5:子树1:1、2、3、4、6、7 ans[5]=6;
删除6:子树1:1、2、3、4、5、7 ans[6]=6;
删除7:子树1:1、2、3、4、5、6 ans[7]=6;
因此,树的重心为cnt=min(ans[i],cnt)=2;
POJ 1655 http://poj.org/problem?id=1655
题目大意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果有多个重心即size相同就选取编号最小的。
CODE:
POJ 3107 http://poj.org/problem?id=3107
题目大意:给定一棵树,求树的所有重心,按照编号从小到大的顺序输出。
CODE:
两个都是模板题,主要还是对树的重心的理解。简单的DFS的应用,记录每次删除当前结点之后每个子树的最大节点数,最小化最大节点数就是树的重心,在一棵树中,树的重心可能不止一个。
换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
eg:
删除1:子树1:2、6 子树2:4、5 子树3:3、7 ans[1]=2;
删除2:子树1:6 子树2:1、3、4、5、7 ans[2]=5;
删除3:子树1:7 子树2:1、2、4、5、6 ans[3]=5;
删除4:子树1:5 子树2:1、2、3、6、7 ans[4]=5;
删除5:子树1:1、2、3、4、6、7 ans[5]=6;
删除6:子树1:1、2、3、4、5、7 ans[6]=6;
删除7:子树1:1、2、3、4、5、6 ans[7]=6;
因此,树的重心为cnt=min(ans[i],cnt)=2;
POJ 1655 http://poj.org/problem?id=1655
题目大意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果有多个重心即size相同就选取编号最小的。
CODE:
const int maxn=500005; int tot=0,n; int ans,size; int sx[maxn],head[maxn]; int vis[maxn]; struct edge { int to,next; } eg[maxn]; void add(int u,int v) { eg[tot].to=v; eg[tot].next=head[u]; head[u]=tot++; } void init() { tot=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); } void dfs(int u) { vis[u]=1; sx[u]=1; int tmp=0; for(int i=head[u]; i!=-1; i=eg[i].next) { int v=eg[i].to; if(!vis[v]) { dfs(v); sx[u]+=sx[v]; tmp=max(tmp,sx[v]); } } tmp=max(tmp,n-sx[u]); if(size>tmp||size==tmp&&ans>u) { ans=u; size=tmp; } } int main() { int t; scanf("%d",&t); while(t--) { init(); int u,v; scanf("%d",&n); for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } size=INF; dfs(1); printf("%d %d\n",ans,size); } }
POJ 3107 http://poj.org/problem?id=3107
题目大意:给定一棵树,求树的所有重心,按照编号从小到大的顺序输出。
CODE:
const int maxn=100005; struct node { int to,next; } eg[maxn]; int tot=0,num=0,n; int vis[maxn],sx[maxn],ans[maxn]; int head[maxn]; void add(int u,int v) { eg[tot].to=v; eg[tot].next=head[u]; head[u]=tot++; } int size,cnt; void dfs(int u) { vis[u]=1; sx[u]=1; int tmp=0; for(int i=head[u]; i!=-1; i=eg[i].next) { int v=eg[i].to; if(!vis[v]) { dfs(v); sx[u]+=sx[v]; tmp=max(tmp,sx[v]); } } tmp=max(tmp,n-sx[u]); if(tmp<size) { //printf("&&&&&&\n"); num=0; size=tmp; ans[num++]=u; } else if(tmp==size) { //printf("*********\n"); ans[num++]=u; } } void init() { tot=0,num=0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(ans,0,sizeof(ans)); size=INF; } int main() { while(~scanf("%d",&n)) { init(); int u,v; for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); sort(ans,ans+num); for(int i=0; i<num; i++) { if(i) printf(" "); printf("%d",ans[i]); } printf("\n"); } return 0; }
两个都是模板题,主要还是对树的重心的理解。简单的DFS的应用,记录每次删除当前结点之后每个子树的最大节点数,最小化最大节点数就是树的重心,在一棵树中,树的重心可能不止一个。
相关文章推荐
- poj 1655(3107、2378) 求树的重心
- 树的重心 poj - 1655 和 poj - 3107
- poj 1655 and 3107 and 2378 树形dp(树的重心问题)
- POJ 1655 Balancing Act&&POJ 3107 Godfather(树的重心)
- 求树的重心 POJ 1655、POJ 3107 树形DP
- 【poj 1655,3107】树的重心(树形dp)
- poj 3107 Godfather(树的重心)
- poj 3107 Godfather(树的重心问题)
- poj 1655 Balancing Act 树的重心
- POJ 1655 Balancing Act(求树的重心)
- poj-1655-树的重心
- POJ 1655 Balancing Act (求树的重心)
- poj1655(树的重心)
- POJ 1655 树的重心 解题报告
- POJ 1655 (树dp or 树重心)
- POJ 1655 Balancing Act (树的重心)
- poj 1655 Balancing Act【树的重心】
- POJ1655-树的重心&树形dp-Balancing Act
- poj 1655 树的重心
- POJ 1655 树的重心(树形 DP)