POJ 4045 - Power Station(树形DP)

来源:互联网 发布:淘宝uv pv什么意思 编辑:程序博客网 时间:2024/05/14 10:39

题目:

http://poj.org/problem?id=4045

题意:

n个节点,n-1条边。求出以哪个点作为基地时,其他点到这个点的总权值最小。输出最小的总权值以及基地。

思路:

树形DP

num[u]: u点的所有子树节点个数。dp[u][0]: u点的所有子树节点到u的总距离。

dp[u][1]: 除u点的所有子树节点以外的节点到u点的总距离。

f[v][1] = (f[u][0]-f[v][0]-num[v]) + f[u][1] + n - num[v] (画个图就知道了)

AC.

#include <iostream>#include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std;const int maxn = 50005;vector<int> g[maxn];int n;int num[maxn], vis[maxn];long long dp[maxn][2];void init(){    for(int i = 0; i <= n; ++i) {        g[i].clear();    }    memset(num, 0, sizeof(num));    memset(vis, 0, sizeof(vis));    memset(dp, 0, sizeof(dp));}void dfs(int u){    vis[u] = 1;    num[u] = 1;    for(int i = 0; i < g[u].size(); ++i) {        int v = g[u][i];        if(vis[v]) continue;        dfs(v);        num[u] += num[v];        dp[u][0] += dp[v][0];    }    dp[u][0] += num[u]-1;    return;}long long ans;void ddfs(int u){    vis[u] = 1;    for(int i = 0; i < g[u].size(); ++i) {        int v = g[u][i];        if(vis[v]) continue;        dp[v][1] = (dp[u][0] - dp[v][0] - num[v]) + dp[u][1] + n-num[v];        //printf("(%d, %d) %d %d %d %d\n", u, v, dp[u][0], dp[v][0], num[v], dp[u][1]);        ddfs(v);    }    ans = min(ans, dp[u][0] + dp[u][1]);}int main(){    //freopen("in", "r", stdin);    int T;    scanf("%d", &T);    while(T--) {        int I, R;        scanf("%d %d %d", &n, &I, &R);        init();        for(int i = 0; i < n-1; ++i) {            int u, v;            scanf("%d %d", &u, &v);            g[u].push_back(v);            g[v].push_back(u);        }        dfs(1);        memset(vis, 0, sizeof(vis));        ans = 1e18;        //printf("%I64d\n", ans);        ddfs(1);        bool fir = 0;        printf("%I64d\n", ans*I*I*R);        for(int i = 1; i <= n; ++i) {            if(dp[i][0]+dp[i][1] == ans) {                if(!fir) {                    fir = 1;                    printf("%d", i);                }                else {                    printf(" %d", i);                }            }        }        printf("\n\n");    }    return 0;}

另一种思路:

树的重心的定义:子树节点<= n/2, 而每一棵树的重心不会超过2个。

所以求出树的重心之后以重心为根遍历整棵树求出距离。

http://acm.hust.edu.cn/vjudge/contest/viewSource.action?id=4156687

0 0
原创粉丝点击