数的重心(图论深搜)

数的重心

题目描述:给定一颗树,树中包含 nn 个结点(编号 1∼n1∼n)和 n−1n−1 条无向边。

请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。

重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

输入格式

第一行包含整数 n,表示树的结点数。

接下来 n−1行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。

输出格式

输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。

数据范围

1≤n≤10^5

输入样例

 9
 1 2
 1 7
 1 4
 2 8
 2 5
 4 3
 3 9
 4 6

输出样例:

 4

code:

 #include<cstdio>
 #include<cstring>
 #include<iostream>
 #include<algorithm>
 using namespace std;
 
 const int N = 1e5 + 10,M = 2 * N;//N为点的最大个数,M为边数的最大
 int h[N],e[M],ne[M];//h存的是每个结点,e存的是当前边指向的点的值,ne存的是下一条边的编号
 bool st[N];
 int ans = N;
 int n,idx;
 void add(int a,int b){//典型的图的数组模拟邻接表存储
     //结构和哈希表类似,
     e[idx] = b;
     ne[idx] = h[a];
     h[a] = idx++;
 }
 
 int dfs(int u){//该函数返回的是以u为根的子树中结点的总个数
     st[u] = true;
     int sum = 1;//sum存储该子树的结点总个数
     int res = 0;//用来存储去掉根后各个连通块中最大结点数
     for(int i=h[u];i!=-1;i=ne[i]){
         int j = e[i];//j为当前边指向的点
         if(!st[j]){
             int t = dfs(j);//返回j子分支上的结点数
             sum += t;//更新子树结点总数
             res = max(res,t);//更新连通块中的最大结点个数
        }
    }
     
     res = max(n - sum,res);//鉴于搜索是单方向的,因为设置了bool数组防止重复遍历,
     //所以这里会有一个方向(从u-(父亲)过来的连通块)不会被遍历。那么就要通过结点总数减去sum来求得,再比较即可。
     
     ans = min(res,ans);
     return sum;
 }
 int main(){
     cin>>n;
     memset(h,-1,sizeof h);
     for(int i=0;i<n-1;i++){
         int a,b;
         cin>>a>>b;
         add(a,b);
         add(b,a);//设置a到b的边,b到a的边
    }
     
     dfs(n);//参数可以为1~n的任意一个数,只要是题目中出现的结点编号皆可。
     cout<<ans<<endl;
     return 0;
 }

 

posted @ 2021-05-18 22:46  how_you_make_me_feel  阅读(145)  评论(0编辑  收藏  举报