HDOJ 3899 JLUCPC

题意:n个地点构成一棵树,第 i 个地点有 t_i 个人,现要选一个地点开会,求所有人行走距离之和的最小值。N<=10^5

分析:先任选一个地点,求出总代价,然后就能求出相邻点的代价,一遍dfs就能求出所有点的代价。

dfs会爆栈,需要开内存挂:#pragma comment(linker, "/STACK:1024000000,1024000000")

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100001

#pragma comment(linker, "/STACK:1024000000,1024000000")

typedef __int64 LL;

int n,t[N],e,sum;
int first[N],next[N<<1],v[N<<1],w[N<<1];
LL dp[N],tsum[N],ans[N];
void init()
{
    e=sum=0;
    memset(first,-1,sizeof(first));
}
void add(int a,int b,int c)
{
    v[e]=b;
    w[e]=c;
    next[e]=first[a];
    first[a]=e++;
}
void DP(int a,int fa)
{
    dp[a]=0;
    tsum[a]=t[a];
    int i,b;
    for(i=first[a];~i;i=next[i])
    {
        b=v[i];
        if(b==fa)   continue;
        DP(b,a);
        tsum[a]+=tsum[b];
        dp[a]+=dp[b]+tsum[b]*w[i];
    }
}
void dfs(int a,int fa,LL cost)
{
    int i,b;
    for(i=first[a];~i;i=next[i])
    {
        b=v[i];
        if(b^fa)    dfs(b,a,ans[b]=cost+(sum-2*tsum[b])*w[i]);
    }
}
int main()
{
    int a,b,c;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t[i]);
            sum+=t[i];
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        DP(1,0);
        dfs(1,0,ans[1]=dp[1]);
        LL ANS=ans[1];
        for(int i=2;i<=n;i++)   ANS=min(ANS,ans[i]);
        printf("%I64d\n",ANS);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/algorithms/p/2689081.html