树的重心(树形DP)

来源:互联网 发布:手机知乎怎么查看问题 编辑:程序博客网 时间:2024/06/01 08:27

这里写图片描述
树的质心的定义:以这个点为根,那么所有的子树的大小(不包括整个树)不会超过整体大小的一半。

只需要每次比较max{d[son]},和N-d[node],每次保存最大的值,再从最大的值里面保存最小的值,这样的话从上往下搜的时候就会有一个上下子树的大小关系变化的那个结点,即为重心。
代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <vector>#include <iostream>using namespace std;int N; // 1<= N <= 20000const int maxn = 20000;vector<int> tree[maxn + 5]; // tree[i]表示节点i的相邻节点int d[maxn + 5]; // d[i]表示以i为根的子树的节点个数#define INF 10000000int minNode;int minBalance;void dfs(int node, int parent) // node and its parent{    d[node] = 1; // the node itself    int maxSubTree = 0; // subtree that has the most number of nodes    for (int i = 0; i < tree[node].size(); i++) {        int son = tree[node][i];        if (son != parent) {            dfs(son, node);            d[node] += d[son];            maxSubTree = max(maxSubTree, d[son]);        }    }    maxSubTree = max(maxSubTree, N - d[node]); // "upside substree with (N - d[node]) nodes"    if (maxSubTree < minBalance){        minBalance = maxSubTree;        minNode = node;    }}int main(){    int t;    scanf("%d", &t);    while (t--){        scanf("%d", &N);        for (int i = 1; i <= N - 1; i++){            tree[i].clear();        }        for (int i = 1; i <= N-1; i++){            int u, v;            scanf("%d%d", &u, &v);            tree[u].push_back(v);            tree[v].push_back(u);        }        minNode = 0;        minBalance = INF;        dfs(1, 0); // fist node as root        printf("%d %d\n", minNode, minBalance);    }    return 0;}