Algorithm basis---AcWing 846. The center of gravity of the tree DFS

Link to the original question .

Problem Description

Given a tree, the tree contains n nodes (numbered 1~n) and n-1 undirected edges.

Please find the center of gravity of the tree, and output the maximum number of points in the remaining connected blocks after the center of gravity is deleted.

Definition of center of gravity: center of gravity refers to a node in the tree. If the maximum number of points in the remaining connected blocks is the smallest after this point is deleted, then this node is called the center of gravity of the tree.

Input format The
first line contains an integer n, which represents the number of nodes in the tree.

Next n-1 lines, each line contains two integers a and b, indicating that there is an edge between point a and point b.

Output format
Output an integer m, representing the number of nodes of the largest subtree among all the subtrees of the center of gravity.

data range

1≤n≤105

Input sample

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

Sample output:

4

problem analysis

Find the center of gravity of an unrooted tree, and the definition of the center of gravity is the smallest value of the remaining connected blocks after deleting the center of gravity of the tree.
Therefore, first choose a node as the root, traverse all the nodes of the whole unrooted tree, and try to delete this node, find the maximum value of all connected blocks, and finally find the minimum of these maximum values ​​is the answer.
In the process of dfs, you can easily obtain the node tree of the subtree that has not been traversed, that is, the number of connected blocks. You only need to find the node tree of the entire subtree in the process of dfs. :

d [ i ] = ∑ d [ j ] + 1 d[i] = \sum{d[j]}+ 1 d[i]=d [ j ]+1
But how to get the number of nodes in the connected block where the traversed nodes are located?
The sum of points -d[j] is the result.
image

C++ code implementation

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e5+10,M = 2*N;//无向边是节点数二倍
//考了几天试,连静态邻接表都差点不会写了。。。
int e[M], ne[M], head[N];
bool st[N];
int idex = 0, ans = N, n;

//a, b之间加一条a->b的边
void add(int a, int b){
    
    
    e[idex] = b;
    ne[idex] = head[a];
    head[a] = idex++;
}
//深度遍历节点x,求出节点x为根的节点数,并尝试删除x更新ans
//返回子树x的节点数
int dfs(int x) {
    
    
    int m = 0;//各棵子树的最大节点数
    int sum = 1;//记录整个子树的节点总数
    st[x] = true;
    //遍历直接相连的节点,求出各棵子树的节点数
    for(int i = head[x]; i != -1; i = ne[i]) {
    
    
        //只计算未访问过的节点
        int j = e[i];
        if(!st[j]) {
    
    
            int temp = dfs(j);
            m = max(m, temp);
            sum += temp;
        }
    }
    //最后一块连通块是包括其根节点的块,用总节点数减去其子树节点数即可
    m = max(m, n-sum);
    ans = min(ans, m);
    return sum;
}

int main() {
    
    
    cin>>n;
    //建图
    memset(head, -1, sizeof head);
    for(int i = 0 ; i < n-1 ; ++ i ) {
    
    
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y);
        add(y, x);
    }
    //深搜求解
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

Guess you like

Origin blog.csdn.net/mwl000000/article/details/108503963