树的重心
Posted wolf940509
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树的重心相关的知识,希望对你有一定的参考价值。
树的重心:对于一棵n个结点的无根树,找到一个点,使得把树变成以该点为根的有根树树时,最大子树的结点数最小。关于重心的求法见《算法竞赛入门经典第二版》281页
下面来看两个基础的题目:
分析:求出树的重心以及最大子树的结点数
1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "string" 5 #include "vector" 6 using namespace std; 7 const int maxn=20000+10; 8 const int INF=1<<30; 9 int T,n; 10 vector<int> g[maxn]; 11 int wide[maxn],f[maxn],dp[maxn],son[maxn]; 12 int wide_max; 13 void init(){ 14 scanf("%d",&n); 15 for(int i=0;i<=n;i++) 16 g[i].clear(); 17 for(int i=1;i<n;i++){ 18 int x,y; 19 scanf("%d%d",&x,&y); 20 g[x].push_back(y); 21 g[y].push_back(x); 22 } 23 } 24 void dfs(int v,int fa){ 25 int d=g[v].size(); 26 if(fa==-1) 27 wide[v]=0; 28 else 29 wide[v]=wide[fa]+1; 30 if(wide_max<wide[v]) 31 wide_max=wide[v]; 32 for(int i=0;i<d;i++){ 33 int k=g[v][i]; 34 if(k!=fa){ 35 dfs(k,f[k]=v); 36 } 37 } 38 } 39 void treeDP(int root){ 40 f[root]=-1; 41 wide_max=-1; 42 dfs(root,-1); 43 for(int i=wide_max;i>=0;i--){ 44 for(int j=1;j<=n;j++){ 45 if(wide[j]==i){ 46 dp[j]=son[j]+1; 47 if(i>=1) 48 son[f[j]]+=dp[j]; 49 } 50 } 51 } 52 } 53 int main() 54 { 55 cin>>T; 56 while(T--){ 57 init(); 58 memset(son,0,sizeof(son)); 59 memset(dp,0,sizeof(dp)); 60 treeDP(1); 61 int s=INF,pos; 62 for(int i=1;i<=n;i++){ 63 int d=g[i].size(); 64 int ans=n-dp[i]; 65 for(int j=0;j<d;j++){ 66 int k=g[i][j]; 67 if(k!=f[i]){ 68 ans=max(ans,dp[k]); 69 } 70 } 71 if(ans<s){ 72 s=ans; 73 pos=i; 74 } 75 } 76 printf("%d %d\n",pos,s); 77 } 78 return 0; 79 }
分析:求出数的所有重心,这个题时间卡得比较紧,不能用vector建图,要用链式前向星,关于链式前向星,这里有一篇很好的博客[点我]。同时要求我们在边求解的过程当中边标记。
1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "string" 5 using namespace std; 6 const int maxn=50000+10; 7 const int INF=1<<30; 8 int n,cnt,s; 9 int dp[maxn],f[maxn],vis[maxn]; 10 int head[maxn*2]; 11 struct Node 12 { 13 int to,next,w; 14 }; 15 Node edge[maxn*2]; 16 void add(int x,int y){ 17 edge[cnt].to=y; 18 edge[cnt].next=head[x]; 19 head[x]=cnt++; 20 } 21 void init(){ 22 scanf("%d",&n); 23 memset(head,-1,sizeof(head)); 24 cnt=0; 25 for(int i=1;i<n;i++){ 26 int x,y; 27 scanf("%d%d",&x,&y); 28 add(x,y); 29 add(y,x); 30 } 31 } 32 int dfs(int v,int fa){ 33 f[v]=fa; 34 dp[v]=1; 35 for(int i=head[v];i!=-1;i=edge[i].next){ 36 int k=edge[i].to; 37 if(k!=f[v]){ 38 dp[v]+=dfs(k,v); 39 } 40 } 41 int ans=n-dp[v]; 42 for(int i=head[v];i!=-1;i=edge[i].next){ 43 int k=edge[i].to; 44 if(k==f[v]) continue; 45 ans=max(ans,dp[k]); 46 } 47 vis[v]=ans; 48 s=min(ans,s); 49 return dp[v]; 50 } 51 int main() 52 { 53 init(); 54 s=INF; 55 dfs(1,-1); 56 for(int i=1;i<=n;i++){ 57 if(vis[i]==s) 58 printf("%d ",i); 59 } 60 printf("\n"); 61 }
以上是关于树的重心的主要内容,如果未能解决你的问题,请参考以下文章