链接:点击打开链接
题意:给出一棵树每个点的权值和每条边的长度,点j到点i的代价为点j的权值乘以连接i和j的边的长度,输出点x,使得所有点到x点的代价最小
代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
long long dp[100005],vis[100005];
long long sum,ans[100005],val[100005];
struct node{
long long to,cost;
node(long long x,long long y){
to=x;
cost=y;
}
};
vector<node> G[100005];
void dfs1(long long s,long long sum){
long long i,tmp,cnt;
vis[s]=1;
for(i=0;i<G[s].size();i++){
tmp=G[s][i].to;
if(vis[tmp])
continue;
cnt=sum+G[s][i].cost;
ans[1]+=cnt*val[tmp]; //求出根节点的值
dfs1(tmp,cnt);
dp[s]+=dp[tmp]; //并求出每个节点所有子树节点权值的和
}
}
void dfs2(long long s){
long long i,tmp;
vis[s]=1;
for(i=0;i<G[s].size();i++){
tmp=G[s][i].to;
if(vis[tmp])
continue;
ans[tmp]=ans[s]+(sum-dp[tmp])*G[s][i].cost-dp[tmp]*G[s][i].cost;
dfs2(tmp); //画图就可以看出父节点的值和子节点的值的关系
}
}
int main(){ //这类题都是求出根节点的值,再由一些关系推出每个节点的值
long long n,i,j,u,v,w,sol;
while(scanf("%I64d",&n)!=EOF){
sum=0;
for(i=1;i<=n;i++)
G[i].clear();
for(i=1;i<=n;i++){
scanf("%I64d",&dp[i]);
val[i]=dp[i];
sum+=val[i];
}
for(i=1;i<n;i++){
scanf("%I64d%I64d%I64d",&u,&v,&w);
G[u].push_back(node(v,w));
G[v].push_back(node(u,w));
}
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
dfs1(1,0);
memset(vis,0,sizeof(vis));
dfs2(1);
sol=ans[1]; //注意不要开成0x3f3f3f3f
for(i=2;i<=n;i++)
sol=min(sol,ans[i]);
printf("%I64d\n",sol);
}
return 0;
}