POJ 1655 Balancing Act (树形DP求树的重心)

题意:

求一棵树中以某个点为重心最小的子树集, 就是去掉这个点, 图中节点最多的联通块节点最少。

分析:

想知道这个点是不是最优的点, 只要比较它子树的数量和除去这部分其他的数量(它的父节点那部分树), 最后循环一遍找最优即可。

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;

const int maxn = 25000 + 7;
const int inf = 1e9 + 7;
int Max[maxn];//记录以该节点为重心,子树节点的最大值
int Num[maxn];//记录包括该节点不回溯到父亲节点有多少个子节点
vector<int> G[maxn];
int N;
void init() {
    for(int i = 0; i < maxn; i ++) {
        G[i].clear();
    }
}
void dpMax(int u, int pre) {

    Num[u] = 1, Max[u] = 0;

    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(v == pre)
            continue;
        dpMax(v, u);
        Max[u] = max(Max[u], Num[v]);
        Num[u] += Num[v];
    }
    Max[u] = max(Max[u], N - Num[u]);//比较一下自己子树和父亲子树的最大值

}
int main() {
    int T;
    cin >> T;
    while(T--) {
        init();
        cin >> N;
        for(int i = 0; i < N - 1; i++) {
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
//        Max[0] = inf;
        dpMax(1, -1);
        int ansNum = inf, ansInd = 1;
        for(int i = 1; i <= N; i++){
            if(ansNum > Max[i]){
                ansNum = Max[i];
                ansInd = i;
            }
        }
        cout << ansInd << " " << ansNum << "\n";
    }
    return 0;
}

 

posted @ 2018-06-08 14:46  Neord  阅读(106)  评论(0)    收藏  举报