Tree Cutting (树形DP)

来源:互联网 发布:姓氏头像制作软件 编辑:程序博客网 时间:2024/05/21 21:35


题意:给一个树状图,有n个点。求出,去掉哪个点,使得剩下的每个连通子图中点的数量不超过n/2。如果有很多这样的点,就按升序输出。n<=10000

思路:此题是求解树的重心的一个变形,首先要知道什么是树的重心。不明白的先移步树的重心了解一下。

根据求解树的重心的方法,设f[i] 为 以i为根的子树的结点个数,那么 f[i] += {f[j] + 1 | j 为i的子结点} 。

设dp[i] 为删除结点i, 最大的连通图有多少个结点。最后答案将d[i] <= n / 2 的结点 i 输出即可



/*********************************************** * Author: fisty * Created Time: 2015/2/22 17:18:44 * File Name   : poj2378.cpp *********************************************** */#include <iostream>#include <cstring>#include <deque>#include <cmath>#include <queue>#include <stack>#include <list>#include <map>#include <set>#include <string>#include <vector>#include <cstdio>#include <bitset>#include <algorithm>using namespace std;#define Debug(x) cout << #x << " " << x <<endl#define Memset(x, a) memset(x, a, sizeof(x))const int INF = 0x3f3f3f3f;typedef long long LL;typedef pair<int, int> P;#define FOR(i, a, b) for(int i = a;i < b; i++)#define MAX_N 10100int n;vector<int> G[MAX_N];int f[MAX_N], dp[MAX_N];void dfs(int u, int fa){    //dp[u] : 把 u 节点删掉之后子连通图里结点数量的最大值    f[u] = 1;    int _max = -INF;//结点u的子孙结点中的最大值    for(int i = 0;i < G[u].size(); i++){        int v = G[u][i];        if(v == fa) continue;        dfs(v, u);        f[u] += f[v];        _max = max(_max, f[v]);    }    dp[u] = max(_max, n - f[u]);}int main() {    //freopen("in.cpp", "r", stdin);    cin.tie(0);    ios::sync_with_stdio(false);    cin >> n;     int limit = n / 2;    FOR(i, 0, n-1){        int u, v;        cin >> u >> v;        G[u].push_back(v);        G[v].push_back(u);    }    dfs(1, -1);    int first = 0;    for(int i = 1;i <= n; i++){        if(dp[i] <= limit){            cout << i << endl;        }    }    return 0;}


0 0
原创粉丝点击