题目链接:http://poj.org/problem?id=1655
题目大意:树的重心:找到一个点作为新的树根,其所有的子树中最大子树的节点数最少,那么这个点就是这个树的重心。树的重心的意义在于,删去重心后,生成的多棵树尽可能平衡。
分析:一次搜索即可。DFS每一个点s,找出其各个子树的节点数,纪录最大值son[s],然后比较balance=max(son[s],n-son[s]-1)即为最终结果。
实现代码如下(vector容器纪录边==>125MS):
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int M=20005; vector <int> adj[M]; int n; //节点数 int son[M]; //该节点的儿子节点数 bool vis[M]; int ans,asize; void dfs(int s) { vis[s]=1; son[s]=0; int balance=0; int len=adj[s].size(); for(int j=0;j<len;j++) { int u=adj[s][j]; if(vis[u]) continue; dfs(u); son[s]+=son[u]+1; balance=max(balance,son[u]+1); } balance=max(balance,n-son[s]-1); if(balance<asize||(balance==asize&&s<ans)) { ans=s; asize=balance; } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) adj[i].clear(); for(int i=1;i<=n-1;i++) { int u,v; scanf("%d%d",&u,&v); adj[u].push_back(v); adj[v].push_back(u); } memset(vis,0,sizeof(vis)); asize=M; dfs(1); printf("%d %d\n",ans,asize); } return 0; }
前向星纪录边-实现代码如下==>47MS(可见前向星要比vector省去很多时间):
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int maxn=20005; struct note { int v,next; }edge[maxn*2]; int head[maxn],ip; int maxx,point,n,num[maxn]; void init() { memset(head,-1,sizeof(head)); ip=0; } void addedge(int u,int v) { edge[ip].v=v,edge[ip].next=head[u],head[u]=ip++; } void dfs(int u,int pre) { int tmp=-0x3f3f3f3f; num[u]=1; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==pre)continue; dfs(v,u); num[u]+=num[v]; tmp=max(tmp,num[v]); } tmp=max(tmp,n-num[u]);///除去以u为根节点的子树部分剩下的节点数 if(tmp<maxx||tmp==maxx&&u<point) { point=u; maxx=tmp; } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); init(); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } memset(num,0,sizeof(num)); maxx=0x3f3f3f3f; dfs(1,-1); printf("%d %d\n",point,maxx); } return 0; }