树形dp
首先先一遍dfs撸出以1为集会地点的不方便值以及以各点为根的子节点个数(包括自己)sum[i]
然后f[i]=f[j]+(s-sum[j])*c-sum[j]*c;
其中c就是i到j的长度,s为总节点个数,i为j的父亲,f[i]为以i为集会地点的不方便值。
没错连左儿子右兄弟都不用搞
今天发现了头文件的新写法。。只要一行。。
代码:
#include<bits/stdc++.h>
#define g getchar()
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=g;
for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
return x*f;
}
inline void out(ll x){
int a[25],t=0;
if(x<0)putchar('-'),x=-x;
for(;x;x/=10)a[++t]=x%10;
for(int i=t;i;--i)putchar('0'+a[i]);
if(t==0)putchar('0');
putchar('\n');
}
ll head[100005],sum[100005],dis[100005],a[100005],s,ans,n,e;
struct re{int v,w,next;}ed[200005];
inline void ins(int x,int y,int z){
ed[++e]=(re){y,z,head[x]};head[x]=e;
}
void dp(int x,int f){
for(int i=head[x];i;i=ed[i].next){
if(ed[i].v!=f){
dp(ed[i].v,x);
sum[x]+=sum[ed[i].v];
dis[x]+=dis[ed[i].v]+sum[ed[i].v]*ed[i].w;
}
}
sum[x]+=a[x];
}
void dp2(int x,int f,int e){
if(x!=1){
dis[x]=(s-sum[x])*e-sum[x]*e+dis[f];
ans=min(dis[x],ans);
}
for(int i=head[x];i;i=ed[i].next){
if(ed[i].v!=f){
dp2(ed[i].v,x,ed[i].w);
}
}
}
int main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read(),s+=a[i];
for(int i=1;i<n;++i){
int x=read(),y=read(),z=read();
ins(x,y,z);
ins(y,x,z);
}
dp(1,0);
ans=dis[1];
dp2(1,0,0);
out(ans);
return 0;
}

本文详细介绍了一种基于树形结构的动态规划方法——树形DP,并提供了完整的代码示例。通过该方法可以有效地计算出以各个节点作为集合点时的不便值,适用于解决特定类型的最优化问题。
2796

被折叠的 条评论
为什么被折叠?



