您的位置:首页 > 其它

POJ 4045 - Power Station(树形DP)

2015-07-26 23:04 357 查看
题目:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ