树的重心

树的重心:对于一棵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 }
View Code

 链接

分析:求出数的所有重心,这个题时间卡得比较紧,不能用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 }
View Code

 

posted @ 2017-08-17 13:16  wolf940509  阅读(409)  评论(0编辑  收藏  举报