题意:一棵树,给出每个点的权值和每条边的长度,
点j到点i的代价为点j的权值乘以连接i和j的边的长度。求点x使得所有点到点x的代价最小,输出
虽然还是不太懂树形DP是什么意思,先把代码贴出来把。
这道题目的做法是:先进行一次DFS,以每个节点为根,求出它下面节点到它的数量和。
再进行一次DFS,以每个节点为根,求出它下面节点到它的花费总和。
source code:
#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define ll long long
#define Max(a,b) (((a) > (b)) ? (a) : (b))
#define Min(a,b) (((a) < (b)) ? (a) : (b))
#define Abs(x) (((x) > 0) ? (x) : (-(x)))
using namespace std; const int INF = 0x3f3f3f3f;
const int MAXN = ; struct edge{
int v, w;
edge(){}
edge(int a, int b) : v(a), w(b){}
}; vector <edge> node[MAXN];
int n,sum[MAXN],a[MAXN];
//a[MAXN]表示每一个节点的权值,sum[MAXN]表示子树的权值和
ll dist[MAXN];
bool vis[MAXN]; void init(){
for(ll i = ; i <= n; ++i)
node[i].clear();
memset(vis, , sizeof(vis));
memset(dist,,sizeof(dist));
} void dfs(ll u,ll dis){
vis[u] = true;
dist[] += dis * a[u];
sum[u] = a[u];
ll size = node[u].size();
for(ll i = ; i < size; ++i){
ll v = node[u][i].v;
if(vis[v]) continue;
dfs(v, dis + node[u][i].w);
sum[u] += sum[v];
}
} void dfs1(ll u){
vis[u] = true;
ll size = node[u].size();
for(ll i = ; i < size; ++i){
ll v = node[u][i].v;
ll w = node[u][i].w;
if(vis[v]) continue;
dist[v] = dist[u] - sum[v] * w + (sum[] - sum[v]) * w;
//dist[v] = dist[u] + (sum[1] - 2 * sum[v]) * w;
dfs1(v);
}
} int main(){
ll i, j, x, y, w;
while(EOF != scanf("%I64d",&n)){
init();
for(i = ; i <= n; ++i) scanf("%I64d",&a[i]);
for(i = ; i < n; ++i){
scanf("%I64d %I64d %I64d",&x,&y,&w);
node[x].push_back(edge(y,w));
node[y].push_back(edge(x,w));
}
dfs(,);
memset(vis,,sizeof(vis));
dfs1();
ll ans = dist[];
for(i = ; i <= n; ++i){
ans = min(ans, dist[i]);
}
cout << ans << endl;
//printf("%I64d\n",ans);
}
return ;
}