题目:http://poj.org/problem?id=1655
题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的.
分析:首先要知道什么是树的重心,树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重
心后,生成的多棵树尽可能平衡. 实际上树的重心在树的点分治中有重要的作用, 可以避免N^2的极端复杂度(从退化链的一端出发),保证
NlogN的复杂度, 利用树型dp可以很好地求树的重心.
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 20005; const int INF = 1<<30; int head[N]; int son[N]; bool vis[N]; int cnt,n; int ans,size; struct Edge { int to; int next; }; Edge edge[2*N]; void Init() { cnt = 0; size = INF; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void dfs(int cur) { vis[cur] = 1; son[cur] = 0; int tmp = 0; for(int i=head[cur];~i;i=edge[i].next) { int u = edge[i].to; if(!vis[u]) { dfs(u); son[cur] += son[u] + 1; tmp = max(tmp,son[u] + 1); } } tmp = max(tmp,n-son[cur]-1); if(tmp < size || tmp == size && cur < ans) { ans = cur; size = tmp; } } int main() { int T; scanf("%d",&T); while(T--) { Init(); scanf("%d",&n); for(int i=1;i<=n-1;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); printf("%d %d\n",ans,size); } return 0; }
题目:http://poj.org/problem?id=3107
题意:给定一棵树,求树的所有重心,按照编号从小到大的顺序输出.
分析:本题与上题基本上一样,只是求的量不同,既然我们在找树的重心的时候用的树型dp,而且是求的子树中节点数的最大值,然后求所有最
大值的最小值,那么就有可能存在多个重心,我们每更新到一个最小值的时候就记录其它的最小值也为这个最小值的重心,这样下去就会找到所
有的重心.
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int N = 50005; const int INF = 1<<30; int head[N]; int son[N]; bool vis[N]; int cnt,n; int num,size; int ans[N]; struct Edge { int to; int next; }; Edge edge[2*N]; void Init() { cnt = 0; num = 0; size = INF; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void dfs(int cur) { vis[cur] = 1; son[cur] = 0; int tmp = 0; for(int i=head[cur];~i;i=edge[i].next) { int u = edge[i].to; if(!vis[u]) { dfs(u); son[cur] += son[u] + 1; tmp = max(tmp,son[u] + 1); } } tmp = max(tmp,n-son[cur]-1); if(tmp < size) { num = 1; ans[0] = cur; size = tmp; } else if(tmp == size) { ans[num++] = cur; } } int main() { while(~scanf("%d",&n)) { Init(); for(int i=1;i<=n-1;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); sort(ans,ans+num); for(int i=0;i<num;i++) printf("%d ",ans[i]); puts(""); } return 0; }